Merge branch 'newdesign' into 'master'
New Style for Chat Windows See merge request gajim/gajim!144
This commit is contained in:
commit
347f0a8aad
|
@ -30,7 +30,7 @@
|
|||
import os
|
||||
import time
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gio
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Pango
|
||||
from gi.repository import GLib
|
||||
|
@ -58,13 +58,6 @@ from gajim.common.exceptions import GajimGeneralException
|
|||
from gajim.common.const import AvatarSize
|
||||
|
||||
from gajim.command_system.implementation.hosts import ChatCommands
|
||||
|
||||
try:
|
||||
from gajim import gtkspell
|
||||
HAS_GTK_SPELL = True
|
||||
except (ImportError, ValueError):
|
||||
HAS_GTK_SPELL = False
|
||||
|
||||
from gajim.chat_control_base import ChatControlBase
|
||||
|
||||
################################################################################
|
||||
|
@ -95,60 +88,10 @@ class ChatControl(ChatControlBase):
|
|||
self.last_recv_message_marks = None
|
||||
self.last_message_timestamp = None
|
||||
|
||||
# for muc use:
|
||||
# widget = self.xml.get_object('muc_window_actions_button')
|
||||
self.actions_button = self.xml.get_object('message_window_actions_button')
|
||||
id_ = self.actions_button.connect('clicked',
|
||||
self.on_actions_button_clicked)
|
||||
self.handlers[id_] = self.actions_button
|
||||
|
||||
self._formattings_button = self.xml.get_object('formattings_button')
|
||||
self.emoticons_button = self.xml.get_object('emoticons_button')
|
||||
self.toggle_emoticons()
|
||||
|
||||
self._add_to_roster_button = self.xml.get_object(
|
||||
'add_to_roster_button')
|
||||
id_ = self._add_to_roster_button.connect('clicked',
|
||||
self._on_add_to_roster_menuitem_activate)
|
||||
self.handlers[id_] = self._add_to_roster_button
|
||||
|
||||
self._audio_button = self.xml.get_object('audio_togglebutton')
|
||||
id_ = self._audio_button.connect('toggled', self.on_audio_button_toggled)
|
||||
self.handlers[id_] = self._audio_button
|
||||
# add a special img
|
||||
gtkgui_helpers.add_image_to_button(self._audio_button,
|
||||
'gajim-mic_inactive')
|
||||
|
||||
self._video_button = self.xml.get_object('video_togglebutton')
|
||||
id_ = self._video_button.connect('toggled', self.on_video_button_toggled)
|
||||
self.handlers[id_] = self._video_button
|
||||
# add a special img
|
||||
gtkgui_helpers.add_image_to_button(self._video_button,
|
||||
'gajim-cam_inactive')
|
||||
|
||||
self._send_file_button = self.xml.get_object('send_file_button')
|
||||
# add a special img for send file button
|
||||
pixbuf = gtkgui_helpers.get_icon_pixmap('document-send', quiet=True)
|
||||
img = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
self._send_file_button.set_image(img)
|
||||
id_ = self._send_file_button.connect('clicked',
|
||||
self._on_send_file_menuitem_activate)
|
||||
self.handlers[id_] = self._send_file_button
|
||||
|
||||
self._convert_to_gc_button = self.xml.get_object(
|
||||
'convert_to_gc_button')
|
||||
id_ = self._convert_to_gc_button.connect('clicked',
|
||||
self._on_convert_to_gc_menuitem_activate)
|
||||
self.handlers[id_] = self._convert_to_gc_button
|
||||
|
||||
self._contact_information_button = self.xml.get_object(
|
||||
'contact_information_button')
|
||||
id_ = self._contact_information_button.connect('clicked',
|
||||
self._on_contact_information_menuitem_activate)
|
||||
self.handlers[id_] = self._contact_information_button
|
||||
|
||||
compact_view = app.config.get('compact_view')
|
||||
self.chat_buttons_set_visible(compact_view)
|
||||
self.widget_set_visible(self.xml.get_object('banner_eventbox'),
|
||||
app.config.get('hide_chat_banner'))
|
||||
|
||||
|
@ -161,10 +104,9 @@ class ChatControl(ChatControlBase):
|
|||
# Add lock image to show chat encryption
|
||||
self.lock_image = self.xml.get_object('lock_image')
|
||||
|
||||
# Convert to GC icon
|
||||
img = self.xml.get_object('convert_to_gc_button_image')
|
||||
img.set_from_pixbuf(gtkgui_helpers.load_icon(
|
||||
'muc_active').get_pixbuf())
|
||||
# Menu for the HeaderBar
|
||||
self.control_menu = gui_menu_builder.get_singlechat_menu(
|
||||
self.control_id)
|
||||
|
||||
self._audio_banner_image = self.xml.get_object('audio_banner_image')
|
||||
self._video_banner_image = self.xml.get_object('video_banner_image')
|
||||
|
@ -270,7 +212,7 @@ class ChatControl(ChatControlBase):
|
|||
|
||||
# Enable encryption if needed
|
||||
self.no_autonegotiation = False
|
||||
|
||||
self.add_actions()
|
||||
self.update_ui()
|
||||
self.set_lock_image()
|
||||
|
||||
|
@ -298,6 +240,107 @@ class ChatControl(ChatControlBase):
|
|||
# PluginSystem: adding GUI extension point for this ChatControl
|
||||
# instance object
|
||||
app.plugin_manager.gui_extension_point('chat_control', self)
|
||||
self.update_actions()
|
||||
|
||||
def add_actions(self):
|
||||
actions = [
|
||||
('send-file-', self._on_send_file),
|
||||
('invite-contacts-', self._on_invite_contacts),
|
||||
('add-to-roster-', self._on_add_to_roster),
|
||||
('information-', self._on_information),
|
||||
]
|
||||
|
||||
for action in actions:
|
||||
action_name, func = action
|
||||
act = Gio.SimpleAction.new(action_name + self.control_id, None)
|
||||
act.connect("activate", func)
|
||||
self.parent_win.window.add_action(act)
|
||||
|
||||
act = Gio.SimpleAction.new_stateful(
|
||||
'toggle-audio-' + self.control_id, None,
|
||||
GLib.Variant.new_boolean(False))
|
||||
act.connect('change-state', self._on_audio)
|
||||
self.parent_win.window.add_action(act)
|
||||
|
||||
act = Gio.SimpleAction.new_stateful(
|
||||
'toggle-video-' + self.control_id,
|
||||
None, GLib.Variant.new_boolean(False))
|
||||
act.connect('change-state', self._on_video)
|
||||
self.parent_win.window.add_action(act)
|
||||
|
||||
def update_actions(self):
|
||||
win = self.parent_win.window
|
||||
online = app.account_is_connected(self.account)
|
||||
|
||||
# Add to roster
|
||||
if not isinstance(self.contact, GC_Contact) \
|
||||
and _('Not in Roster') in self.contact.groups and \
|
||||
app.connections[self.account].roster_supported and online:
|
||||
win.lookup_action(
|
||||
'add-to-roster-' + self.control_id).set_enabled(True)
|
||||
else:
|
||||
win.lookup_action(
|
||||
'add-to-roster-' + self.control_id).set_enabled(False)
|
||||
|
||||
# Audio
|
||||
win.lookup_action('toggle-audio-' + self.control_id).set_enabled(
|
||||
online and self.audio_available)
|
||||
|
||||
# Video
|
||||
win.lookup_action('toggle-video-' + self.control_id).set_enabled(
|
||||
online and self.video_available)
|
||||
|
||||
# Send file
|
||||
if ((self.contact.supports(NS_FILE) or \
|
||||
self.contact.supports(NS_JINGLE_FILE_TRANSFER_5)) and \
|
||||
(self.type_id == 'chat' or self.gc_contact.resource)) and \
|
||||
self.contact.show != 'offline' and online:
|
||||
win.lookup_action('send-file-' + self.control_id).set_enabled(
|
||||
True)
|
||||
else:
|
||||
win.lookup_action('send-file-' + self.control_id).set_enabled(
|
||||
False)
|
||||
|
||||
# Convert to GC
|
||||
if app.config.get_per('accounts', self.account, 'is_zeroconf'):
|
||||
win.lookup_action(
|
||||
'invite-contacts-' + self.control_id).set_enabled(False)
|
||||
else:
|
||||
if self.contact.supports(NS_MUC) and online:
|
||||
win.lookup_action(
|
||||
'invite-contacts-' + self.control_id).set_enabled(True)
|
||||
else:
|
||||
win.lookup_action(
|
||||
'invite-contacts-' + self.control_id).set_enabled(False)
|
||||
|
||||
# Information
|
||||
win.lookup_action(
|
||||
'information-' + self.control_id).set_enabled(online)
|
||||
|
||||
def _on_send_file(self, action, param):
|
||||
super()._on_send_file()
|
||||
|
||||
def _on_add_to_roster(self, action, param):
|
||||
dialogs.AddNewContactWindow(self.account, self.contact.jid)
|
||||
|
||||
def _on_information(self, action, param):
|
||||
app.interface.roster.on_info(None, self.contact, self.account)
|
||||
|
||||
def _on_invite_contacts(self, action, param):
|
||||
"""
|
||||
User wants to invite some friends to chat
|
||||
"""
|
||||
dialogs.TransformChatToMUC(self.account, [self.contact.jid])
|
||||
|
||||
def _on_audio(self, action, param):
|
||||
action.set_state(param)
|
||||
state = param.get_boolean()
|
||||
self.on_jingle_button_toggled(state, 'audio')
|
||||
|
||||
def _on_video(self, action, param):
|
||||
action.set_state(param)
|
||||
state = param.get_boolean()
|
||||
self.on_jingle_button_toggled(state, 'video')
|
||||
|
||||
def subscribe_events(self):
|
||||
"""
|
||||
|
@ -329,14 +372,6 @@ class ChatControl(ChatControlBase):
|
|||
self._formattings_button.set_tooltip_text(_('This contact does '
|
||||
'not support HTML'))
|
||||
|
||||
# Add to roster
|
||||
if not isinstance(self.contact, GC_Contact) \
|
||||
and _('Not in Roster') in self.contact.groups and \
|
||||
app.connections[self.account].roster_supported:
|
||||
self._add_to_roster_button.show()
|
||||
else:
|
||||
self._add_to_roster_button.hide()
|
||||
|
||||
# Jingle detection
|
||||
if self.contact.supports(NS_JINGLE_ICE_UDP) and \
|
||||
app.HAVE_FARSTREAM and self.contact.resource:
|
||||
|
@ -348,63 +383,6 @@ class ChatControl(ChatControlBase):
|
|||
self.video_available = False
|
||||
self.audio_available = False
|
||||
|
||||
# Audio buttons
|
||||
self._audio_button.set_sensitive(self.audio_available)
|
||||
|
||||
# Video buttons
|
||||
self._video_button.set_sensitive(self.video_available)
|
||||
|
||||
# change tooltip text for audio and video buttons if farstream is
|
||||
# not installed
|
||||
audio_tooltip_text = _('Toggle audio session') + '\n'
|
||||
video_tooltip_text = _('Toggle video session') + '\n'
|
||||
if not app.HAVE_FARSTREAM:
|
||||
ext_text = _('Feature not available, see Help->Features')
|
||||
self._audio_button.set_tooltip_text(audio_tooltip_text + ext_text)
|
||||
self._video_button.set_tooltip_text(video_tooltip_text + ext_text)
|
||||
elif not self.audio_available :
|
||||
ext_text =_('Feature not supported by remote client')
|
||||
self._audio_button.set_tooltip_text(audio_tooltip_text + ext_text)
|
||||
self._video_button.set_tooltip_text(video_tooltip_text + ext_text)
|
||||
else:
|
||||
self._audio_button.set_tooltip_text(audio_tooltip_text[:-1])
|
||||
self._video_button.set_tooltip_text(video_tooltip_text[:-1])
|
||||
|
||||
# Send file
|
||||
if ((self.contact.supports(NS_FILE) or \
|
||||
self.contact.supports(NS_JINGLE_FILE_TRANSFER_5)) and \
|
||||
(self.type_id == 'chat' or self.gc_contact.resource)) and \
|
||||
self.contact.show != 'offline':
|
||||
self._send_file_button.set_sensitive(True)
|
||||
self._send_file_button.set_tooltip_text(_('Send files'))
|
||||
else:
|
||||
self._send_file_button.set_sensitive(False)
|
||||
if not (self.contact.supports(NS_FILE) or self.contact.supports(
|
||||
NS_JINGLE_FILE_TRANSFER_5)):
|
||||
self._send_file_button.set_tooltip_text(_(
|
||||
"This contact does not support file transfer."))
|
||||
else:
|
||||
self._send_file_button.set_tooltip_text(
|
||||
_("You need to know the real JID of the contact to send "
|
||||
"them a file."))
|
||||
|
||||
# Convert to GC
|
||||
if app.config.get_per('accounts', self.account, 'is_zeroconf'):
|
||||
self._convert_to_gc_button.set_no_show_all(True)
|
||||
self._convert_to_gc_button.hide()
|
||||
else:
|
||||
if self.contact.supports(NS_MUC):
|
||||
self._convert_to_gc_button.set_sensitive(True)
|
||||
else:
|
||||
self._convert_to_gc_button.set_sensitive(False)
|
||||
|
||||
# Information
|
||||
if app.account_is_disconnected(self.account):
|
||||
self._contact_information_button.set_sensitive(False)
|
||||
else:
|
||||
self._contact_information_button.set_sensitive(True)
|
||||
|
||||
|
||||
def update_all_pep_types(self):
|
||||
for pep_type in self._pep_images:
|
||||
self.update_pep(pep_type)
|
||||
|
@ -751,12 +729,12 @@ class ChatControl(ChatControlBase):
|
|||
getattr(self, '_' + jingle_type + '_button').set_active(False)
|
||||
getattr(self, 'update_' + jingle_type)()
|
||||
|
||||
def on_jingle_button_toggled(self, widget, jingle_type):
|
||||
def on_jingle_button_toggled(self, state, jingle_type):
|
||||
img_name = 'gajim-%s_%s' % ({'audio': 'mic', 'video': 'cam'}[jingle_type],
|
||||
{True: 'active', False: 'inactive'}[widget.get_active()])
|
||||
{True: 'active', False: 'inactive'}[state])
|
||||
path_to_img = gtkgui_helpers.get_icon_path(img_name)
|
||||
|
||||
if widget.get_active():
|
||||
if state:
|
||||
if getattr(self, jingle_type + '_state') == \
|
||||
self.JINGLE_STATE_NULL:
|
||||
if jingle_type == 'video':
|
||||
|
@ -795,12 +773,6 @@ class ChatControl(ChatControlBase):
|
|||
img = getattr(self, '_' + jingle_type + '_button').get_property('image')
|
||||
img.set_from_file(path_to_img)
|
||||
|
||||
def on_audio_button_toggled(self, widget):
|
||||
self.on_jingle_button_toggled(widget, 'audio')
|
||||
|
||||
def on_video_button_toggled(self, widget):
|
||||
self.on_jingle_button_toggled(widget, 'video')
|
||||
|
||||
def set_lock_image(self):
|
||||
loggable = self.session and self.session.is_loggable()
|
||||
|
||||
|
@ -832,10 +804,6 @@ class ChatControl(ChatControlBase):
|
|||
self.authentication_button.set_tooltip_text(tooltip)
|
||||
self.widget_set_visible(self.authentication_button, not visible)
|
||||
context = self.msg_scrolledwindow.get_style_context()
|
||||
if visible:
|
||||
context.add_class('authentication')
|
||||
else:
|
||||
context.remove_class('authentication')
|
||||
self.lock_image.set_sensitive(visible)
|
||||
|
||||
def _on_authentication_button_clicked(self, widget):
|
||||
|
@ -1205,10 +1173,7 @@ class ChatControl(ChatControlBase):
|
|||
self.handlers[i].disconnect(i)
|
||||
del self.handlers[i]
|
||||
self.conv_textview.del_handlers()
|
||||
if app.config.get('use_speller') and HAS_GTK_SPELL:
|
||||
spell_obj = gtkspell.get_from_text_view(self.msg_textview)
|
||||
if spell_obj:
|
||||
spell_obj.detach()
|
||||
self.remove_speller()
|
||||
self.msg_textview.destroy()
|
||||
# PluginSystem: calling shutdown of super class (ChatControlBase) to let
|
||||
# it remove it's GUI extension points
|
||||
|
@ -1272,10 +1237,18 @@ class ChatControl(ChatControlBase):
|
|||
if not app.config.get('show_avatar_in_chat'):
|
||||
return
|
||||
|
||||
pixbuf = app.contacts.get_avatar(
|
||||
self.account, self.contact.jid, AvatarSize.CHAT)
|
||||
if self.TYPE_ID == message_control.TYPE_CHAT:
|
||||
pixbuf = app.contacts.get_avatar(
|
||||
self.account, self.contact.jid, AvatarSize.CHAT)
|
||||
else:
|
||||
pixbuf = app.interface.get_avatar(
|
||||
self.gc_contact.avatar_sha, AvatarSize.CHAT)
|
||||
|
||||
image = self.xml.get_object('avatar_image')
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
if pixbuf is None:
|
||||
image.set_from_icon_name('avatar-default', Gtk.IconSize.DIALOG)
|
||||
else:
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
|
||||
def _nec_update_avatar(self, obj):
|
||||
if obj.account != self.account:
|
||||
|
@ -1446,15 +1419,6 @@ class ChatControl(ChatControlBase):
|
|||
elif typ == 'pm':
|
||||
control.remove_contact(nick)
|
||||
|
||||
def _on_send_file_menuitem_activate(self, widget):
|
||||
self._on_send_file()
|
||||
|
||||
def _on_add_to_roster_menuitem_activate(self, widget):
|
||||
dialogs.AddNewContactWindow(self.account, self.contact.jid)
|
||||
|
||||
def _on_contact_information_menuitem_activate(self, widget):
|
||||
app.interface.roster.on_info(widget, self.contact, self.account)
|
||||
|
||||
def _on_convert_to_gc_menuitem_activate(self, widget):
|
||||
"""
|
||||
User wants to invite some friends to chat
|
||||
|
@ -1522,21 +1486,11 @@ class ChatControl(ChatControlBase):
|
|||
if contact:
|
||||
self.contact = contact
|
||||
self.draw_banner()
|
||||
self.update_actions()
|
||||
|
||||
def got_disconnected(self):
|
||||
# Add to roster
|
||||
self._add_to_roster_button.hide()
|
||||
# Audio button
|
||||
self._audio_button.set_sensitive(False)
|
||||
# Video button
|
||||
self._video_button.set_sensitive(False)
|
||||
# Send file button
|
||||
self._send_file_button.set_tooltip_text('')
|
||||
self._send_file_button.set_sensitive(False)
|
||||
# Convert to GC button
|
||||
self._convert_to_gc_button.set_sensitive(False)
|
||||
|
||||
ChatControlBase.got_disconnected(self)
|
||||
self.update_actions()
|
||||
|
||||
def update_status_display(self, name, uf_show, status):
|
||||
"""
|
||||
|
|
|
@ -35,16 +35,17 @@ from gi.repository import Pango
|
|||
from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim.gtkgui_helpers import Color
|
||||
from gajim import message_control
|
||||
from gajim import dialogs
|
||||
from gajim import history_window
|
||||
from gajim import notify
|
||||
from gajim import gtkspell
|
||||
import re
|
||||
|
||||
from gajim import emoticons
|
||||
from gajim.scrolled_window import ScrolledWindow
|
||||
from gajim.common import events
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
|
@ -65,11 +66,6 @@ from gajim.command_system.implementation.middleware import CommandTools
|
|||
from gajim.command_system.implementation import standard
|
||||
from gajim.command_system.implementation import execute
|
||||
|
||||
try:
|
||||
from gajim import gtkspell
|
||||
HAS_GTK_SPELL = True
|
||||
except (ImportError, ValueError):
|
||||
HAS_GTK_SPELL = False
|
||||
|
||||
################################################################################
|
||||
class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
||||
|
@ -256,28 +252,21 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
MessageControl.__init__(self, type_id, parent_win, widget_name,
|
||||
contact, acct, resource=resource)
|
||||
|
||||
widget = self.xml.get_object('history_button')
|
||||
# set document-open-recent icon for history button
|
||||
if gtkgui_helpers.gtk_icon_theme.has_icon('document-open-recent'):
|
||||
img = self.xml.get_object('history_image')
|
||||
img.set_from_icon_name('document-open-recent', Gtk.IconSize.MENU)
|
||||
|
||||
id_ = widget.connect('clicked', self._on_history_menuitem_activate)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
# Create banner and connect signals
|
||||
widget = self.xml.get_object('banner_eventbox')
|
||||
id_ = widget.connect('button-press-event',
|
||||
self._on_banner_eventbox_button_press_event)
|
||||
self.handlers[id_] = widget
|
||||
if self.TYPE_ID != message_control.TYPE_GC:
|
||||
# Create banner and connect signals
|
||||
widget = self.xml.get_object('banner_eventbox')
|
||||
id_ = widget.connect('button-press-event',
|
||||
self._on_banner_eventbox_button_press_event)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
self.urlfinder = re.compile(
|
||||
r"(www\.(?!\.)|[a-z][a-z0-9+.-]*://)[^\s<>'\"]+[^!,\.\s<>\)'\"\]]")
|
||||
|
||||
self.banner_status_label = self.xml.get_object('banner_label')
|
||||
id_ = self.banner_status_label.connect('populate_popup',
|
||||
self.on_banner_label_populate_popup)
|
||||
self.handlers[id_] = self.banner_status_label
|
||||
if self.banner_status_label is not None:
|
||||
id_ = self.banner_status_label.connect('populate_popup',
|
||||
self.on_banner_label_populate_popup)
|
||||
self.handlers[id_] = self.banner_status_label
|
||||
|
||||
# Init DND
|
||||
self.TARGET_TYPE_URI_LIST = 80
|
||||
|
@ -332,9 +321,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
|
||||
self.msg_scrolledwindow = ScrolledWindow()
|
||||
self.msg_scrolledwindow.set_max_content_height(100)
|
||||
self.msg_scrolledwindow.set_min_content_height(23)
|
||||
self.msg_scrolledwindow.set_propagate_natural_height(True)
|
||||
self.msg_scrolledwindow.get_style_context().add_class('scrolledtextview')
|
||||
|
||||
self.msg_scrolledwindow.set_property('shadow_type', Gtk.ShadowType.IN)
|
||||
self.msg_scrolledwindow.add(self.msg_textview)
|
||||
|
||||
|
@ -364,8 +352,9 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
self.set_emoticon_popover()
|
||||
|
||||
# Attach speller
|
||||
if app.config.get('use_speller') and HAS_GTK_SPELL:
|
||||
self.set_speller()
|
||||
self.spell = None
|
||||
self.spell_handlers = []
|
||||
self.set_speller()
|
||||
self.conv_textview.tv.show()
|
||||
|
||||
# For XEP-0172
|
||||
|
@ -417,6 +406,28 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
action.connect("change-state", self.change_encryption)
|
||||
self.parent_win.window.add_action(action)
|
||||
|
||||
action = Gio.SimpleAction.new(
|
||||
'browse-history-%s' % self.control_id, GLib.VariantType.new('s'))
|
||||
action.connect('activate', self._on_history)
|
||||
self.parent_win.window.add_action(action)
|
||||
|
||||
# Actions
|
||||
|
||||
def _on_history(self, action, param):
|
||||
"""
|
||||
When history menuitem is pressed: call history window
|
||||
"""
|
||||
jid = param.get_string()
|
||||
if jid == 'none':
|
||||
jid = self.contact.jid
|
||||
|
||||
if 'logs' in app.interface.instances:
|
||||
app.interface.instances['logs'].window.present()
|
||||
app.interface.instances['logs'].open_history(jid, self.account)
|
||||
else:
|
||||
app.interface.instances['logs'] = \
|
||||
history_window.HistoryWindow(jid, self.account)
|
||||
|
||||
def change_encryption(self, action, param):
|
||||
encryption = param.get_string()
|
||||
if encryption == 'disabled':
|
||||
|
@ -467,24 +478,57 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
image.set_from_pixbuf(icon)
|
||||
|
||||
def set_speller(self):
|
||||
# now set the one the user selected
|
||||
if not gtkspell.HAS_GTK_SPELL or not app.config.get('use_speller'):
|
||||
return
|
||||
|
||||
def _on_focus_in(*args):
|
||||
if self.spell is None:
|
||||
return
|
||||
self.spell.attach(self.msg_textview)
|
||||
|
||||
def _on_focus_out(*args):
|
||||
if self.spell is None:
|
||||
return
|
||||
if not self.msg_textview.has_text():
|
||||
self.spell.detach()
|
||||
|
||||
lang = self.get_speller_language()
|
||||
if not lang:
|
||||
return
|
||||
try:
|
||||
self.spell = gtkspell.Spell(self.msg_textview, lang)
|
||||
self.spell.connect('language_changed', self.on_language_changed)
|
||||
handler_id = self.msg_textview.connect('focus-in-event',
|
||||
_on_focus_in)
|
||||
self.spell_handlers.append(handler_id)
|
||||
handler_id = self.msg_textview.connect('focus-out-event',
|
||||
_on_focus_out)
|
||||
self.spell_handlers.append(handler_id)
|
||||
except OSError:
|
||||
dialogs.AspellDictError(lang)
|
||||
app.config.set('use_speller', False)
|
||||
|
||||
def remove_speller(self):
|
||||
if self.spell is None:
|
||||
return
|
||||
self.spell.detach()
|
||||
for id_ in self.spell_handlers:
|
||||
self.msg_textview.disconnect(id_)
|
||||
self.spell_handlers.remove(id_)
|
||||
self.spell = None
|
||||
|
||||
def get_speller_language(self):
|
||||
per_type = 'contacts'
|
||||
if self.type_id == message_control.TYPE_GC:
|
||||
if self.type_id == 'gc':
|
||||
per_type = 'rooms'
|
||||
lang = app.config.get_per(per_type, self.contact.jid,
|
||||
'speller_language')
|
||||
lang = app.config.get_per(
|
||||
per_type, self.contact.jid, 'speller_language')
|
||||
if not lang:
|
||||
# use the default one
|
||||
lang = app.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = app.LANG
|
||||
if lang:
|
||||
try:
|
||||
self.spell = gtkspell.Spell(self.msg_textview, lang)
|
||||
self.msg_textview.lang = lang
|
||||
self.spell.connect('language_changed', self.on_language_changed)
|
||||
except (GObject.GError, RuntimeError, TypeError, OSError):
|
||||
dialogs.AspellDictError(lang)
|
||||
return lang or None
|
||||
|
||||
def on_language_changed(self, spell, lang):
|
||||
per_type = 'contacts'
|
||||
|
@ -492,9 +536,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
per_type = 'rooms'
|
||||
if not app.config.get_per(per_type, self.contact.jid):
|
||||
app.config.add_per(per_type, self.contact.jid)
|
||||
app.config.set_per(per_type, self.contact.jid, 'speller_language',
|
||||
lang)
|
||||
self.msg_textview.lang = lang
|
||||
app.config.set_per(
|
||||
per_type, self.contact.jid, 'speller_language', lang)
|
||||
|
||||
def on_banner_label_populate_popup(self, label, menu):
|
||||
"""
|
||||
|
@ -549,6 +592,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
menu.show_all()
|
||||
|
||||
def on_quote(self, widget, text):
|
||||
self.msg_textview.remove_placeholder()
|
||||
text = '>' + text.replace('\n', '\n>') + '\n'
|
||||
message_buffer = self.msg_textview.get_buffer()
|
||||
message_buffer.insert_at_cursor(text)
|
||||
|
@ -1283,13 +1327,6 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
else:
|
||||
widget.show_all()
|
||||
|
||||
def chat_buttons_set_visible(self, state):
|
||||
"""
|
||||
Toggle chat buttons
|
||||
"""
|
||||
MessageControl.chat_buttons_set_visible(self, state)
|
||||
self.widget_set_visible(self.xml.get_object('actions_hbox'), state)
|
||||
|
||||
def got_connected(self):
|
||||
self.msg_textview.set_sensitive(True)
|
||||
self.msg_textview.set_editable(True)
|
||||
|
@ -1302,3 +1339,19 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
|
|||
|
||||
self.no_autonegotiation = False
|
||||
self.update_toolbar()
|
||||
|
||||
|
||||
class ScrolledWindow(Gtk.ScrolledWindow):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def do_get_preferred_height(self):
|
||||
min_height, natural_height = Gtk.ScrolledWindow.do_get_preferred_height(self)
|
||||
child = self.get_child()
|
||||
if natural_height and self.get_max_content_height() > -1 and child:
|
||||
_, child_nat_height = child.get_preferred_height()
|
||||
if natural_height > child_nat_height:
|
||||
if child_nat_height < 26:
|
||||
return 26, 26
|
||||
|
||||
return min_height, natural_height
|
||||
|
|
|
@ -41,12 +41,6 @@ class StandardCommonCommands(CommandContainer):
|
|||
AUTOMATIC = True
|
||||
HOSTS = ChatCommands, PrivateChatCommands, GroupChatCommands
|
||||
|
||||
@command
|
||||
@doc(_("Hide the chat buttons"))
|
||||
def compact(self):
|
||||
new_status = not self.hide_chat_buttons
|
||||
self.chat_buttons_set_visible(new_status)
|
||||
|
||||
@command(overlap=True)
|
||||
@doc(_("Show help on a given command or a list of available commands if -a is given"))
|
||||
def help(self, command=None, all=False):
|
||||
|
|
|
@ -264,7 +264,6 @@ class Config:
|
|||
'show_roster_on_startup':[opt_str, 'always', _('Show roster on startup.\n\'always\' - Always show roster.\n\'never\' - Never show roster.\n\'last_state\' - Restore the last state roster.')],
|
||||
'show_avatar_in_chat': [opt_bool, True, _('If False, you will no longer see the avatar in the chat window.')],
|
||||
'escape_key_closes': [opt_bool, True, _('If True, pressing the escape key closes a tab/window.')],
|
||||
'compact_view': [opt_bool, False, _('Hides the buttons in chat windows.')],
|
||||
'hide_groupchat_banner': [opt_bool, False, _('Hides the banner in a group chat window')],
|
||||
'hide_chat_banner': [opt_bool, False, _('Hides the banner in two persons chat window')],
|
||||
'hide_groupchat_occupants_list': [opt_bool, False, _('Hides the group chat occupants list in group chat window.')],
|
||||
|
|
|
@ -2342,6 +2342,13 @@ class Connection(CommonConnection, ConnectionHandlers):
|
|||
if rule['type'] == 'group':
|
||||
roster.draw_group(rule['value'], self.name)
|
||||
|
||||
def bookmarks_available(self):
|
||||
if self.private_storage_supported:
|
||||
return True
|
||||
if self.pubsub_publish_options_supported:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _request_bookmarks_xml(self):
|
||||
if not app.account_is_connected(self.name):
|
||||
return
|
||||
|
|
|
@ -30,8 +30,8 @@ class OptionType(IntEnum):
|
|||
|
||||
class AvatarSize(IntEnum):
|
||||
ROSTER = 32
|
||||
CHAT = 48
|
||||
NOTIFICATION = 48
|
||||
CHAT = 52
|
||||
PROFILE = 64
|
||||
TOOLTIP = 125
|
||||
VCARD = 200
|
||||
|
|
|
@ -50,12 +50,7 @@ from gajim import message_control
|
|||
from gajim.chat_control_base import ChatControlBase
|
||||
from gajim import dataforms_widget
|
||||
from gajim import gui_menu_builder
|
||||
|
||||
try:
|
||||
from gajim import gtkspell
|
||||
HAS_GTK_SPELL = True
|
||||
except (ImportError, ValueError):
|
||||
HAS_GTK_SPELL = False
|
||||
from gajim import gtkspell
|
||||
|
||||
from gajim.common import helpers
|
||||
from gajim.common import app
|
||||
|
@ -187,16 +182,12 @@ class PreferencesWindow:
|
|||
else:
|
||||
show_roster_combobox.set_active(0)
|
||||
|
||||
# Compact View
|
||||
st = app.config.get('compact_view')
|
||||
self.xml.get_object('compact_view_checkbutton').set_active(st)
|
||||
|
||||
# Ignore XHTML
|
||||
st = app.config.get('ignore_incoming_xhtml')
|
||||
self.xml.get_object('xhtml_checkbutton').set_active(st)
|
||||
|
||||
# use speller
|
||||
if HAS_GTK_SPELL:
|
||||
if gtkspell.HAS_GTK_SPELL:
|
||||
st = app.config.get('use_speller')
|
||||
self.xml.get_object('speller_checkbutton').set_active(st)
|
||||
else:
|
||||
|
@ -657,12 +648,6 @@ class PreferencesWindow:
|
|||
config_type = c_config.opt_show_roster_on_startup[active]
|
||||
app.config.set('show_roster_on_startup', config_type)
|
||||
|
||||
def on_compact_view_checkbutton_toggled(self, widget):
|
||||
active = widget.get_active()
|
||||
for ctrl in self._get_all_controls():
|
||||
ctrl.chat_buttons_set_visible(active)
|
||||
app.config.set('compact_view', active)
|
||||
|
||||
def on_xhtml_checkbutton_toggled(self, widget):
|
||||
self.on_checkbutton_toggled(widget, 'ignore_incoming_xhtml')
|
||||
helpers.update_optional_features()
|
||||
|
@ -670,23 +655,13 @@ class PreferencesWindow:
|
|||
def apply_speller(self):
|
||||
for ctrl in self._get_all_controls():
|
||||
if isinstance(ctrl, ChatControlBase):
|
||||
try:
|
||||
spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
|
||||
except (TypeError, RuntimeError, OSError):
|
||||
spell_obj = None
|
||||
|
||||
if not spell_obj:
|
||||
ctrl.set_speller()
|
||||
ctrl.set_speller()
|
||||
|
||||
def remove_speller(self):
|
||||
for ctrl in self._get_all_controls():
|
||||
if isinstance(ctrl, ChatControlBase):
|
||||
try:
|
||||
spell_obj = gtkspell.get_from_text_view(ctrl.msg_textview)
|
||||
except (TypeError, RuntimeError):
|
||||
spell_obj = None
|
||||
if spell_obj:
|
||||
spell_obj.detach()
|
||||
if ctrl.spell is not None:
|
||||
ctrl.remove_speller()
|
||||
|
||||
def on_speller_checkbutton_toggled(self, widget):
|
||||
active = widget.get_active()
|
||||
|
@ -695,15 +670,10 @@ class PreferencesWindow:
|
|||
lang = app.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = app.LANG
|
||||
tv = Gtk.TextView()
|
||||
try:
|
||||
gtkspell.Spell(tv, lang)
|
||||
except (TypeError, RuntimeError, OSError):
|
||||
dialogs.ErrorDialog(
|
||||
_('Dictionary for lang %s not available') % lang,
|
||||
_('You have to install %s dictionary to use spellchecking, or '
|
||||
'choose another language by setting the speller_language option.'
|
||||
) % lang)
|
||||
|
||||
available = gtkspell.test_language(lang)
|
||||
if not available:
|
||||
dialogs.AspellDictError(lang)
|
||||
app.config.set('use_speller', False)
|
||||
widget.set_active(False)
|
||||
else:
|
||||
|
|
|
@ -374,7 +374,6 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkEventBox" id="banner_eventbox">
|
||||
<property name="name">ChatControl-BannerEventBox</property>
|
||||
|
@ -385,16 +384,23 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="banner_status_image">
|
||||
<object class="GtkEventBox" id="avatar_eventbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="ypad">5</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="visible_window">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="avatar_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -545,21 +551,15 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEventBox" id="avatar_eventbox">
|
||||
<object class="GtkImage" id="banner_status_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="visible_window">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="avatar_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
</object>
|
||||
</child>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -573,94 +573,16 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="vbox106">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
|
||||
<property name="height_request">60</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
|
||||
<property name="height_request">60</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="emoticons_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">face-smile</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="msgtextview-button"/>
|
||||
<class name="left"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="authentication_button">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="lock_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="msgtextview-button"/>
|
||||
<class name="right"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="scrolled-no-border"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
|
@ -669,9 +591,48 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="actions_hbox">
|
||||
<object class="GtkSeparator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="chatcontrol-separator"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="emoticons_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Show a list of emoticons (Alt+M)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">face-smile-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="formattings_button">
|
||||
<property name="visible">True</property>
|
||||
|
@ -686,23 +647,13 @@
|
|||
<object class="GtkImage" id="image10">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-bold</property>
|
||||
<property name="icon_name">format-text-bold-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="vseparator1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<style>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -711,235 +662,15 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_to_roster_button">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_markup" translatable="yes">Add this contact to roster (Ctrl+D)</property>
|
||||
<property name="tooltip_text" translatable="yes">Add this contact to roster (Ctrl+D)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image9">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="send_file_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="audio_togglebutton">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="audio_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="video_togglebutton">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="video_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="convert_to_gc_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_markup" translatable="yes">Invite contacts to the conversation (Ctrl+G)</property>
|
||||
<property name="tooltip_text" translatable="yes">Invite contacts to the conversation (Ctrl+G)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="convert_to_gc_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="contact_information_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_markup" translatable="yes">Show the contact&apos;s profile (Ctrl+I)</property>
|
||||
<property name="tooltip_text" translatable="yes">Show the contact's profile (Ctrl+I)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-info</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="history_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_markup" translatable="yes">Browse the chat history (Ctrl+H)</property>
|
||||
<property name="tooltip_text" translatable="yes">Browse the chat history (Ctrl+H)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="history_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-justify-fill</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="vseparator3">
|
||||
<object class="GtkComboBox" id="label_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="orientation">vertical</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">9</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="message_window_actions_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_markup" translatable="yes">Show advanced functions (Alt+D)</property>
|
||||
<property name="tooltip_text" translatable="yes">Show advanced functions (Alt+D)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-execute</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">10</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="encryption_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Choose an encryption</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">channel-secure-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">11</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -1042,26 +773,70 @@ audio-mic-volume-low</property>
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">12</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="label_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<object class="GtkButton" id="authentication_button">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="lock_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-dialog-authentication</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="encryption_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Choose an encryption</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">channel-secure-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">13</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -2,6 +2,82 @@
|
|||
<!-- Generated with glade 3.20.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkMenu" id="formattings_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkCheckMenuItem" id="bold">
|
||||
<property name="name">bold</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Bold</property>
|
||||
<signal name="activate" handler="on_formatting_menuitem_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckMenuItem" id="italic">
|
||||
<property name="name">italic</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Italic</property>
|
||||
<signal name="activate" handler="on_formatting_menuitem_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckMenuItem" id="underline">
|
||||
<property name="name">underline</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Underline</property>
|
||||
<signal name="activate" handler="on_formatting_menuitem_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckMenuItem" id="strike">
|
||||
<property name="name">strike</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Strike</property>
|
||||
<signal name="activate" handler="on_formatting_menuitem_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="color">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Color</property>
|
||||
<signal name="activate" handler="on_color_menuitem_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="font">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Font</property>
|
||||
<signal name="activate" handler="on_font_menuitem_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="clear_formatting">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Clear formatting</property>
|
||||
<signal name="activate" handler="on_clear_formatting_menuitem_activate" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkBox" id="groupchat_control_hbox">
|
||||
<property name="can_focus">True</property>
|
||||
<child>
|
||||
|
@ -13,83 +89,6 @@
|
|||
<property name="margin_bottom">7</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkEventBox" id="banner_eventbox">
|
||||
<property name="name">GroupChatControl-BannerEventBox</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox3024">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="gc_banner_status_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="banner_vbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="banner_name_label">
|
||||
<property name="name">GroupChatControl-BannerNameLabel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label"><span weight="heavy" size="large">room jid</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="banner_label">
|
||||
<property name="name">GroupChatControl-BannerLabel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label">label</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned" id="hpaned">
|
||||
<property name="visible">True</property>
|
||||
|
@ -104,7 +103,68 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="margin_right">4</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkEventBox" id="banner_eventbox">
|
||||
<property name="name">GroupChatControl-BannerEventBox</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox3024">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="gc_banner_status_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-missing-image</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="banner_name_label">
|
||||
<property name="name">GroupChatControl-BannerNameLabel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label"><span weight="heavy" size="large">room jid</span></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkActionBar" id="banner_actionbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="actionbar-no-border"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="conversation_scrolledwindow">
|
||||
<property name="width_request">200</property>
|
||||
|
@ -115,11 +175,28 @@
|
|||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<style>
|
||||
<class name="scrolled-no-border"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="chatcontrol-separator"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -138,12 +215,11 @@
|
|||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">face-smile</property>
|
||||
<property name="icon_name">face-smile-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="msgtextview-button"/>
|
||||
<class name="left"/>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
|
@ -153,7 +229,32 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
<object class="GtkMenuButton" id="formattings_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="relief">none</property>
|
||||
<property name="popup">formattings_menu</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image10">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">format-text-bold-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="authentication_button">
|
||||
|
@ -172,8 +273,7 @@
|
|||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="msgtextview-button"/>
|
||||
<class name="right"/>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
|
@ -183,190 +283,19 @@
|
|||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="actions_hbox">
|
||||
<property name="height_request">34</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="formattings_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Show a list of formattings</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image11">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-bold</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="change_nick_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Change your nickname (Ctrl+N)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-edit</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="change_subject_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Change the room's subject (Alt+T)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="bookmark_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Bookmark this room (Ctrl+B)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="history_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Browse the chat history (Ctrl+H)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="history_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="stock">gtk-justify-fill</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="vseparator4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="muc_window_actions_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Show advanced functions (Alt+D)</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1344">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-execute</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="label_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="no_show_all">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">7</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -383,18 +312,22 @@
|
|||
<property name="icon_name">channel-secure-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="chatcontrol-actionbar-button"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">8</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -422,6 +355,9 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="scrolled-no-border"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">False</property>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.18.3 -->
|
||||
<!-- Generated with glade 3.20.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.12"/>
|
||||
<object class="GtkEventBox" id="chat_tab_ebox">
|
||||
|
@ -28,10 +28,10 @@
|
|||
<property name="width_request">70</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="max_width_chars">9</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -64,15 +64,35 @@
|
|||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkHeaderBar" id="headerbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="header_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkApplicationWindow" id="message_window">
|
||||
<property name="name">MessageWindow</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="default_width">480</property>
|
||||
<property name="default_height">440</property>
|
||||
<property name="show_menubar">False</property>
|
||||
<child>
|
||||
<object class="GtkNotebook" id="notebook">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="scrollable">True</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
@ -426,23 +426,6 @@
|
|||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="compact_view_checkbutton">
|
||||
<property name="label" translatable="yes">Ma_ke message windows compact</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Hide all buttons in chat windows</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_compact_view_checkbutton_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="xhtml_checkbutton">
|
||||
<property name="label" translatable="yes">_Ignore rich content in incoming messages</property>
|
||||
|
@ -457,7 +440,7 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -474,7 +457,7 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -490,7 +473,7 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -555,7 +538,7 @@
|
|||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="top_attach">6</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<requires lib="gtk+" version="3.12"/>
|
||||
<object class="GtkAccelGroup" id="accelgroup1"/>
|
||||
<object class="GtkApplicationWindow" id="roster_window">
|
||||
<property name="name">RosterWindow</property>
|
||||
<property name="width_request">85</property>
|
||||
<property name="height_request">200</property>
|
||||
<property name="can_focus">False</property>
|
||||
|
@ -115,4 +116,28 @@
|
|||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkHeaderBar" id="headerbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title">Gajim</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="header_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="no_show_all">True</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
/* Gajim Application CSS File */
|
||||
|
||||
.msgtextview-button {
|
||||
|
||||
.chatcontrol-actionbar-button {
|
||||
padding: 0px 5px 0px 5px;
|
||||
background-color: @theme_base_color;
|
||||
border: 1px solid;
|
||||
border-radius: 0px;
|
||||
border-color: @borders;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.msgtextview-button:hover, .msgtextview-button:checked {
|
||||
color: @theme_base_color;
|
||||
border-color: @borders;
|
||||
text-shadow: none;
|
||||
-gtk-icon-shadow: none;
|
||||
box-shadow: none;
|
||||
.scrolled-no-border {border: none}
|
||||
.scrolled-no-border undershoot.top, undershoot.bottom { background-image: none; }
|
||||
|
||||
.actionbar-no-border box {border: none}
|
||||
|
||||
.actionbar-no-border button {
|
||||
padding: 0px;
|
||||
background-color: @theme_base_color;
|
||||
border: none;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#MessageWindow, #RosterWindow paned { background-color: @theme_base_color; }
|
||||
|
||||
.msgtextview-button.left { border-right: none; }
|
||||
.msgtextview-button.right { border-left: none; }
|
||||
.scrolledtextview { border:none; }
|
||||
|
||||
.scrolledtextview { border-left:none; }
|
||||
.scrolledtextview.authentication { border-right:none; }
|
||||
.chatcontrol-separator {margin-bottom: 6px;}
|
||||
|
||||
#SubjectPopover box { padding: 10px; }
|
||||
|
||||
/* VCardWindow */
|
||||
.VCard-GtkLinkButton { padding-left: 5px; border-left: none; }
|
||||
|
|
|
@ -42,6 +42,7 @@ from gajim import gtkgui_helpers
|
|||
from gajim import vcard
|
||||
from gajim import conversation_textview
|
||||
from gajim import dataforms_widget
|
||||
from gajim import gtkspell
|
||||
|
||||
from random import randrange
|
||||
from gajim.common import pep
|
||||
|
@ -50,12 +51,6 @@ from gajim.common import const
|
|||
from gajim.options_dialog import OptionsDialog
|
||||
from gajim.common.const import Option, OptionKind, OptionType
|
||||
|
||||
try:
|
||||
from gajim import gtkspell
|
||||
HAS_GTK_SPELL = True
|
||||
except (ImportError, ValueError):
|
||||
HAS_GTK_SPELL = False
|
||||
|
||||
# those imports are not used in this file, but in files that 'import dialogs'
|
||||
# so they can do dialog.GajimThemesWindow() for example
|
||||
from gajim.filetransfers_window import FileTransfersWindow
|
||||
|
@ -1486,11 +1481,11 @@ class FileChooserDialog(Gtk.FileChooserDialog):
|
|||
class AspellDictError:
|
||||
def __init__(self, lang):
|
||||
ErrorDialog(
|
||||
_('Dictionary for lang %s not available') % lang,
|
||||
_('You have to install %s dictionary to use spellchecking, or '
|
||||
'choose another language by setting the speller_language option.'
|
||||
'\n\nHighlighting misspelled words feature will not be used') % lang)
|
||||
app.config.set('use_speller', False)
|
||||
_('Dictionary for lang "%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):
|
||||
"""
|
||||
|
@ -3082,14 +3077,14 @@ class SingleMessageWindow:
|
|||
else:
|
||||
self.to_entry.set_text(to)
|
||||
|
||||
if app.config.get('use_speller') and HAS_GTK_SPELL and action == 'send':
|
||||
if app.config.get('use_speller') and gtkspell.HAS_GTK_SPELL and action == 'send':
|
||||
try:
|
||||
lang = app.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = app.LANG
|
||||
gtkspell.Spell(self.conversation_textview.tv, lang)
|
||||
gtkspell.Spell(self.message_textview, lang)
|
||||
except (GObject.GError, TypeError, RuntimeError, OSError):
|
||||
self.spell = gtkspell.Spell(self.message_textview, lang)
|
||||
self.spell.attach(self.message_textview)
|
||||
except OSError:
|
||||
AspellDictError(lang)
|
||||
|
||||
self.prepare_widgets_for(self.action)
|
||||
|
|
|
@ -289,6 +289,7 @@ class EmoticonPopover(Gtk.Popover):
|
|||
self.append_emoticon(child.get_child().get_text())
|
||||
|
||||
def append_emoticon(self, pix):
|
||||
self.text_widget.remove_placeholder()
|
||||
buffer_ = self.text_widget.get_buffer()
|
||||
if buffer_.get_char_count():
|
||||
buffer_.insert_at_cursor(' ')
|
||||
|
|
|
@ -212,8 +212,15 @@ class GajimApplication(Gtk.Application):
|
|||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(i18n.APP)
|
||||
builder.add_from_file(path)
|
||||
self.set_menubar(builder.get_object("menubar"))
|
||||
self.set_app_menu(builder.get_object("appmenu"))
|
||||
menubar = builder.get_object("menubar")
|
||||
appmenu = builder.get_object("appmenu")
|
||||
if os.name != 'nt':
|
||||
self.set_app_menu(appmenu)
|
||||
else:
|
||||
# Dont set Application Menu for Windows
|
||||
# Add it to the menubar instead
|
||||
menubar.prepend_submenu('Gajim', appmenu)
|
||||
self.set_menubar(menubar)
|
||||
|
||||
def do_activate(self):
|
||||
Gtk.Application.do_activate(self)
|
||||
|
|
|
@ -36,6 +36,7 @@ from gi.repository import Gdk
|
|||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Pango
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import gui_menu_builder
|
||||
from gajim import message_control
|
||||
|
@ -251,15 +252,6 @@ class PrivateChatControl(ChatControl):
|
|||
return
|
||||
self.show_avatar()
|
||||
|
||||
def show_avatar(self):
|
||||
if not app.config.get('show_avatar_in_chat'):
|
||||
return
|
||||
|
||||
pixbuf = app.interface.get_avatar(
|
||||
self.gc_contact.avatar_sha, AvatarSize.CHAT)
|
||||
image = self.xml.get_object('avatar_image')
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
|
||||
def update_contact(self):
|
||||
self.contact = self.gc_contact.as_contact()
|
||||
|
||||
|
@ -274,20 +266,6 @@ class PrivateChatControl(ChatControl):
|
|||
|
||||
self.session.negotiate_e2e(False)
|
||||
|
||||
def prepare_context_menu(self, hide_buttonbar_items=False):
|
||||
"""
|
||||
Set compact view menuitem active state sets active and sensitivity state
|
||||
for history_menuitem (False for tranasports) and file_transfer_menuitem
|
||||
and hide()/show() for add_to_roster_menuitem
|
||||
"""
|
||||
menu = gui_menu_builder.get_contact_menu(self.contact, self.account,
|
||||
use_multiple_contacts=False, show_start_chat=False,
|
||||
show_encryption=True, control=self,
|
||||
show_buttonbar_items=not hide_buttonbar_items,
|
||||
gc_contact=self.gc_contact,
|
||||
is_anonymous=self.room_ctrl.is_anonymous)
|
||||
return menu
|
||||
|
||||
def got_disconnected(self):
|
||||
ChatControl.got_disconnected(self)
|
||||
|
||||
|
@ -317,56 +295,18 @@ class GroupchatControl(ChatControlBase):
|
|||
# Keep error dialog instance to be sure to have only once at a time
|
||||
self.error_dialog = None
|
||||
|
||||
self.actions_button = self.xml.get_object('muc_window_actions_button')
|
||||
id_ = self.actions_button.connect('clicked',
|
||||
self.on_actions_button_clicked)
|
||||
self.handlers[id_] = self.actions_button
|
||||
|
||||
self.emoticons_button = self.xml.get_object('emoticons_button')
|
||||
self.toggle_emoticons()
|
||||
|
||||
widget = self.xml.get_object('change_nick_button')
|
||||
widget.set_sensitive(False)
|
||||
id_ = widget.connect('clicked', self._on_change_nick_menuitem_activate)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
widget = self.xml.get_object('change_subject_button')
|
||||
widget.set_sensitive(False)
|
||||
id_ = widget.connect('clicked',
|
||||
self._on_change_subject_menuitem_activate)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
formattings_button = self.xml.get_object('formattings_button')
|
||||
formattings_button.set_sensitive(False)
|
||||
|
||||
widget = self.xml.get_object('bookmark_button')
|
||||
for bm in app.connections[self.account].bookmarks:
|
||||
if bm['jid'] == self.contact.jid:
|
||||
widget.hide()
|
||||
break
|
||||
else:
|
||||
id_ = widget.connect('clicked',
|
||||
self._on_bookmark_room_menuitem_activate)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
if gtkgui_helpers.gtk_icon_theme.has_icon('bookmark-new'):
|
||||
img = self.xml.get_object('image7')
|
||||
img.set_from_icon_name('bookmark-new', Gtk.IconSize.MENU)
|
||||
widget.set_sensitive(
|
||||
app.connections[self.account].private_storage_supported or \
|
||||
(app.connections[self.account].pep_supported and \
|
||||
app.connections[self.account].pubsub_publish_options_supported))
|
||||
widget.show()
|
||||
|
||||
if gtkgui_helpers.gtk_icon_theme.has_icon('document-open-recent'):
|
||||
img = self.xml.get_object('history_image')
|
||||
img.set_from_icon_name('document-open-recent', Gtk.IconSize.MENU)
|
||||
|
||||
self.current_tooltip = None
|
||||
if parent_win is not None:
|
||||
# On AutoJoin with minimize Groupchats are created without parent
|
||||
# Tooltip Window has to be created with parent
|
||||
# Tooltip Window and Actions have to be created with parent
|
||||
self.set_tooltip()
|
||||
self.add_actions()
|
||||
|
||||
widget = self.xml.get_object('list_treeview')
|
||||
id_ = widget.connect('row_expanded', self.on_list_treeview_row_expanded)
|
||||
|
@ -399,8 +339,6 @@ class GroupchatControl(ChatControlBase):
|
|||
if not self.name:
|
||||
self.name = self.room_jid.split('@')[0]
|
||||
|
||||
compact_view = app.config.get('compact_view')
|
||||
self.chat_buttons_set_visible(compact_view)
|
||||
self.widget_set_visible(self.xml.get_object('banner_eventbox'),
|
||||
app.config.get('hide_groupchat_banner'))
|
||||
self.widget_set_visible(self.xml.get_object('list_scrolledwindow'),
|
||||
|
@ -444,6 +382,10 @@ class GroupchatControl(ChatControlBase):
|
|||
id_ = self.hpaned.connect('notify', self.on_hpaned_notify)
|
||||
self.handlers[id_] = self.hpaned
|
||||
|
||||
# Hide the Roster per default
|
||||
self.hpaned.get_child2().set_no_show_all(True)
|
||||
self.hpaned.get_child2().hide()
|
||||
|
||||
# set the position of the current hpaned
|
||||
hpaned_position = app.config.get('gc-hpaned-position')
|
||||
self.hpaned.set_position(hpaned_position)
|
||||
|
@ -516,6 +458,22 @@ class GroupchatControl(ChatControlBase):
|
|||
gui_menu_builder.get_encryption_menu(self.control_id, self.type_id))
|
||||
self.set_encryption_menu_icon()
|
||||
|
||||
# Banner
|
||||
self.banner_actionbar = self.xml.get_object('banner_actionbar')
|
||||
self.hide_roster_button = Gtk.Button.new_from_icon_name(
|
||||
'go-previous-symbolic', Gtk.IconSize.MENU)
|
||||
self.hide_roster_button.connect('clicked',
|
||||
lambda *args: self.show_roster())
|
||||
self.subject_button = Gtk.MenuButton()
|
||||
self.subject_button.set_image(Gtk.Image.new_from_icon_name(
|
||||
'go-down-symbolic', Gtk.IconSize.MENU))
|
||||
self.subject_button.set_popover(SubjectPopover())
|
||||
self.subject_button.set_no_show_all(True)
|
||||
self.banner_actionbar.pack_end(self.hide_roster_button)
|
||||
self.banner_actionbar.pack_start(self.subject_button)
|
||||
|
||||
self.control_menu = gui_menu_builder.get_groupchat_menu(self.control_id)
|
||||
|
||||
app.ged.register_event_handler('gc-presence-received', ged.GUI1,
|
||||
self._nec_gc_presence_received)
|
||||
app.ged.register_event_handler('gc-message-received', ged.GUI1,
|
||||
|
@ -538,14 +496,199 @@ class GroupchatControl(ChatControlBase):
|
|||
|
||||
self.update_ui()
|
||||
self.widget.show_all()
|
||||
|
||||
# PluginSystem: adding GUI extension point for this GroupchatControl
|
||||
# instance object
|
||||
app.plugin_manager.gui_extension_point('groupchat_control', self)
|
||||
|
||||
def add_actions(self):
|
||||
actions = [
|
||||
('change-subject-', self._on_change_subject),
|
||||
('change-nick-', self._on_change_nick),
|
||||
('disconnect-', self._on_disconnect),
|
||||
('destroy-', self._on_destroy_room),
|
||||
('configure-', self._on_configure_room),
|
||||
('bookmark-', self._on_bookmark_room),
|
||||
('request-voice-', self._on_request_voice),
|
||||
]
|
||||
|
||||
for action in actions:
|
||||
action_name, func = action
|
||||
act = Gio.SimpleAction.new(action_name + self.control_id, None)
|
||||
act.connect("activate", func)
|
||||
self.parent_win.window.add_action(act)
|
||||
|
||||
non_minimized_gc = app.config.get_per(
|
||||
'accounts', self.account, 'non_minimized_gc').split()
|
||||
value = self.contact.jid not in non_minimized_gc
|
||||
|
||||
act = Gio.SimpleAction.new_stateful(
|
||||
'minimize-' + self.control_id, None,
|
||||
GLib.Variant.new_boolean(value))
|
||||
act.connect('change-state', self._on_minimize)
|
||||
self.parent_win.window.add_action(act)
|
||||
|
||||
value = app.config.get_per(
|
||||
'rooms', self.contact.jid, 'notify_on_all_messages')
|
||||
|
||||
act = Gio.SimpleAction.new_stateful(
|
||||
'notify-on-message-' + self.control_id,
|
||||
None, GLib.Variant.new_boolean(value))
|
||||
act.connect('change-state', self._on_notify_on_all_messages)
|
||||
self.parent_win.window.add_action(act)
|
||||
|
||||
def update_actions(self):
|
||||
if self.parent_win is None:
|
||||
return
|
||||
win = self.parent_win.window
|
||||
contact = app.contacts.get_gc_contact(
|
||||
self.account, self.room_jid, self.nick)
|
||||
online = app.gc_connected[self.account][self.room_jid]
|
||||
|
||||
# Destroy Room
|
||||
win.lookup_action('destroy-' + self.control_id).set_enabled(
|
||||
online and contact.affiliation == 'owner')
|
||||
|
||||
# Configure Room
|
||||
win.lookup_action('configure-' + self.control_id).set_enabled(
|
||||
online and contact.affiliation in ('admin', 'owner'))
|
||||
|
||||
# Bookmarks
|
||||
con = app.connections[self.account]
|
||||
bookmark_support = con.bookmarks_available()
|
||||
not_bookmarked = True
|
||||
for bm in con.bookmarks:
|
||||
if bm['jid'] == self.room_jid:
|
||||
not_bookmarked = False
|
||||
break
|
||||
win.lookup_action('bookmark-' + self.control_id).set_enabled(
|
||||
online and bookmark_support and not_bookmarked)
|
||||
|
||||
# Request Voice
|
||||
role = self.get_role(self.nick)
|
||||
win.lookup_action('request-voice-' + self.control_id).set_enabled(
|
||||
online and role == 'visitor')
|
||||
|
||||
# Change Subject
|
||||
# Get this from Room Disco
|
||||
win.lookup_action('change-subject-' + self.control_id).set_enabled(
|
||||
online)
|
||||
|
||||
# Change Nick
|
||||
win.lookup_action('change-nick-' + self.control_id).set_enabled(
|
||||
online)
|
||||
|
||||
# Actions
|
||||
|
||||
def _on_change_subject(self, action, param):
|
||||
def on_ok(subject):
|
||||
# Note, we don't update self.subject since we don't know whether it
|
||||
# will work yet
|
||||
app.connections[self.account].send_gc_subject(
|
||||
self.room_jid, subject)
|
||||
|
||||
dialogs.InputTextDialog(_('Changing Subject'),
|
||||
_('Please specify the new subject:'), input_str=self.subject,
|
||||
ok_handler=on_ok, transient_for=self.parent_win.window)
|
||||
|
||||
def _on_change_nick(self, action, param):
|
||||
if 'change_nick_dialog' in app.interface.instances:
|
||||
app.interface.instances['change_nick_dialog'].dialog.present()
|
||||
else:
|
||||
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,
|
||||
prompt, change_nick=True, transient_for=self.parent_win.window)
|
||||
|
||||
def _on_disconnect(self, action, param):
|
||||
self.force_non_minimizable = True
|
||||
self.parent_win.remove_tab(self, self.parent_win.CLOSE_COMMAND)
|
||||
self.force_non_minimizable = False
|
||||
|
||||
def _on_destroy_room(self, action, param):
|
||||
def on_ok(reason, jid):
|
||||
if jid:
|
||||
# Test jid
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
except Exception:
|
||||
dialogs.ErrorDialog(_('Invalid group chat JID'),
|
||||
_('The group chat JID has not allowed characters.'))
|
||||
return
|
||||
app.connections[self.account].destroy_gc_room(
|
||||
self.room_jid, reason, jid)
|
||||
|
||||
# Ask for a reason
|
||||
dialogs.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,
|
||||
transient_for=self.parent_win.window)
|
||||
|
||||
def _on_configure_room(self, action, param):
|
||||
c = app.contacts.get_gc_contact(
|
||||
self.account, self.room_jid, self.nick)
|
||||
if c.affiliation == 'owner':
|
||||
app.connections[self.account].request_gc_config(self.room_jid)
|
||||
elif c.affiliation == 'admin':
|
||||
if self.room_jid not in app.interface.instances[self.account][
|
||||
'gc_config']:
|
||||
app.interface.instances[self.account]['gc_config'][
|
||||
self.room_jid] = config.GroupchatConfigWindow(self.account,
|
||||
self.room_jid)
|
||||
|
||||
def _on_bookmark_room(self, action, param):
|
||||
"""
|
||||
Bookmark the room, without autojoin and not minimized
|
||||
"""
|
||||
password = app.gc_passwords.get(self.room_jid, '')
|
||||
app.interface.add_gc_bookmark(
|
||||
self.account, self.name, self.room_jid,
|
||||
'0', '0', password, self.nick)
|
||||
|
||||
def _on_request_voice(self, action, param):
|
||||
"""
|
||||
Request voice in the current room
|
||||
"""
|
||||
app.connections[self.account].request_voice(self.room_jid)
|
||||
|
||||
def _on_minimize(self, action, param):
|
||||
"""
|
||||
When a grouchat is minimized, unparent the tab, put it in roster etc
|
||||
"""
|
||||
action.set_state(param)
|
||||
non_minimized_gc = app.config.get_per(
|
||||
'accounts', self.account, 'non_minimized_gc').split()
|
||||
|
||||
minimize = param.get_boolean()
|
||||
if minimize:
|
||||
non_minimized_gc.remove(self.contact.jid)
|
||||
else:
|
||||
non_minimized_gc.append(self.contact.jid)
|
||||
|
||||
app.config.set_per('accounts', self.account,
|
||||
'non_minimized_gc', ' '.join(non_minimized_gc))
|
||||
|
||||
def _on_notify_on_all_messages(self, action, param):
|
||||
action.set_state(param)
|
||||
app.config.set_per('rooms', self.contact.jid,
|
||||
'notify_on_all_messages', param.get_boolean())
|
||||
|
||||
def show_roster(self):
|
||||
new_state = not self.hpaned.get_child2().is_visible()
|
||||
image = self.hide_roster_button.get_image()
|
||||
if new_state:
|
||||
self.hpaned.get_child2().show()
|
||||
image.set_from_icon_name('go-next-symbolic', Gtk.IconSize.MENU)
|
||||
else:
|
||||
self.hpaned.get_child2().hide()
|
||||
image.set_from_icon_name('go-previous-symbolic', Gtk.IconSize.MENU)
|
||||
|
||||
def on_groupchat_maximize(self):
|
||||
self.set_tooltip()
|
||||
self.add_window_actions()
|
||||
self.add_actions()
|
||||
self.update_actions()
|
||||
self.set_lock_image()
|
||||
self._schedule_activity_timers()
|
||||
|
||||
|
@ -823,10 +966,6 @@ class GroupchatControl(ChatControlBase):
|
|||
self.authentication_button.set_tooltip_text(tooltip)
|
||||
self.widget_set_visible(self.authentication_button, not visible)
|
||||
context = self.msg_scrolledwindow.get_style_context()
|
||||
if visible:
|
||||
context.add_class('authentication')
|
||||
else:
|
||||
context.remove_class('authentication')
|
||||
self.lock_image.set_sensitive(visible)
|
||||
|
||||
def _on_authentication_button_clicked(self, widget):
|
||||
|
@ -886,7 +1025,6 @@ class GroupchatControl(ChatControlBase):
|
|||
room jid, subject
|
||||
"""
|
||||
self.name_label.set_ellipsize(Pango.EllipsizeMode.END)
|
||||
self.banner_status_label.set_ellipsize(Pango.EllipsizeMode.END)
|
||||
font_attrs, font_attrs_small = self.get_font_attrs()
|
||||
if self.is_continued:
|
||||
name = self.get_continued_conversation_name()
|
||||
|
@ -896,169 +1034,10 @@ class GroupchatControl(ChatControlBase):
|
|||
self.name_label.set_markup(text)
|
||||
|
||||
if self.subject:
|
||||
subject = helpers.reduce_chars_newlines(self.subject, max_lines=2)
|
||||
subject = GLib.markup_escape_text(subject)
|
||||
subject = GLib.markup_escape_text(self.subject)
|
||||
subject_text = self.urlfinder.sub(self.make_href, subject)
|
||||
subject_text = '<span %s>%s</span>' % (font_attrs_small,
|
||||
subject_text)
|
||||
|
||||
# tooltip must always hold ALL the subject
|
||||
self.event_box.set_tooltip_text(self.subject)
|
||||
self.banner_status_label.set_no_show_all(False)
|
||||
self.banner_status_label.show()
|
||||
else:
|
||||
subject_text = ''
|
||||
self.event_box.set_has_tooltip(False)
|
||||
self.banner_status_label.hide()
|
||||
self.banner_status_label.set_no_show_all(True)
|
||||
|
||||
self.banner_status_label.set_markup(subject_text)
|
||||
|
||||
def prepare_context_menu(self, hide_buttonbar_items=False):
|
||||
"""
|
||||
Set sensitivity state for configure_room
|
||||
"""
|
||||
xml = gtkgui_helpers.get_gtk_builder('gc_control_popup_menu.ui')
|
||||
menu = xml.get_object('gc_control_popup_menu')
|
||||
|
||||
bookmark_room_menuitem = xml.get_object('bookmark_room_menuitem')
|
||||
change_nick_menuitem = xml.get_object('change_nick_menuitem')
|
||||
configure_room_menuitem = xml.get_object('configure_room_menuitem')
|
||||
destroy_room_menuitem = xml.get_object('destroy_room_menuitem')
|
||||
change_subject_menuitem = xml.get_object('change_subject_menuitem')
|
||||
history_menuitem = xml.get_object('history_menuitem')
|
||||
disconnect_menuitem = xml.get_object('disconnect_menuitem')
|
||||
minimize_menuitem = xml.get_object('minimize_menuitem')
|
||||
notify_menuitem = xml.get_object('notify_menuitem')
|
||||
request_voice_menuitem = xml.get_object('request_voice_menuitem')
|
||||
bookmark_separator = xml.get_object('bookmark_separator')
|
||||
separatormenuitem2 = xml.get_object('separatormenuitem2')
|
||||
request_voice_separator = xml.get_object('request_voice_separator')
|
||||
|
||||
if hide_buttonbar_items:
|
||||
change_nick_menuitem.hide()
|
||||
change_subject_menuitem.hide()
|
||||
bookmark_room_menuitem.hide()
|
||||
history_menuitem.hide()
|
||||
bookmark_separator.hide()
|
||||
separatormenuitem2.hide()
|
||||
else:
|
||||
change_nick_menuitem.show()
|
||||
change_subject_menuitem.show()
|
||||
bookmark_room_menuitem.show()
|
||||
history_menuitem.show()
|
||||
bookmark_separator.show()
|
||||
separatormenuitem2.show()
|
||||
for bm in app.connections[self.account].bookmarks:
|
||||
if bm['jid'] == self.room_jid:
|
||||
bookmark_room_menuitem.hide()
|
||||
bookmark_separator.hide()
|
||||
break
|
||||
|
||||
ag = Gtk.accel_groups_from_object(self.parent_win.window)[0]
|
||||
change_nick_menuitem.add_accelerator('activate', ag, Gdk.KEY_n,
|
||||
Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK, Gtk.AccelFlags.VISIBLE)
|
||||
change_subject_menuitem.add_accelerator('activate', ag,
|
||||
Gdk.KEY_t, Gdk.ModifierType.MOD1_MASK, Gtk.AccelFlags.VISIBLE)
|
||||
bookmark_room_menuitem.add_accelerator('activate', ag, Gdk.KEY_b,
|
||||
Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE)
|
||||
history_menuitem.add_accelerator('activate', ag, Gdk.KEY_h,
|
||||
Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE)
|
||||
|
||||
if self.contact.jid not in app.config.get_per('accounts', self.account,
|
||||
'non_minimized_gc').split(' '):
|
||||
minimize_menuitem.set_active(True)
|
||||
notify_menuitem.set_active(app.config.get_per('rooms', self.contact.jid,
|
||||
'notify_on_all_messages'))
|
||||
conn = app.connections[self.account]
|
||||
if not conn.private_storage_supported and (not conn.pep_supported or \
|
||||
not conn.pubsub_publish_options_supported):
|
||||
bookmark_room_menuitem.set_sensitive(False)
|
||||
if app.gc_connected[self.account][self.room_jid]:
|
||||
c = app.contacts.get_gc_contact(self.account, self.room_jid,
|
||||
self.nick)
|
||||
if c.affiliation not in ('owner', 'admin'):
|
||||
configure_room_menuitem.set_sensitive(False)
|
||||
else:
|
||||
configure_room_menuitem.set_sensitive(True)
|
||||
if c.affiliation != 'owner':
|
||||
destroy_room_menuitem.set_sensitive(False)
|
||||
else:
|
||||
destroy_room_menuitem.set_sensitive(True)
|
||||
change_subject_menuitem.set_sensitive(True)
|
||||
change_nick_menuitem.set_sensitive(True)
|
||||
if c.role == 'visitor':
|
||||
request_voice_menuitem.set_sensitive(True)
|
||||
else:
|
||||
request_voice_menuitem.set_sensitive(False)
|
||||
else:
|
||||
# We are not connected to this groupchat, disable unusable menuitems
|
||||
configure_room_menuitem.set_sensitive(False)
|
||||
destroy_room_menuitem.set_sensitive(False)
|
||||
change_subject_menuitem.set_sensitive(False)
|
||||
change_nick_menuitem.set_sensitive(False)
|
||||
request_voice_menuitem.set_sensitive(False)
|
||||
|
||||
# connect the menuitems to their respective functions
|
||||
id_ = bookmark_room_menuitem.connect('activate',
|
||||
self._on_bookmark_room_menuitem_activate)
|
||||
self.handlers[id_] = bookmark_room_menuitem
|
||||
|
||||
id_ = change_nick_menuitem.connect('activate',
|
||||
self._on_change_nick_menuitem_activate)
|
||||
self.handlers[id_] = change_nick_menuitem
|
||||
|
||||
id_ = configure_room_menuitem.connect('activate',
|
||||
self._on_configure_room_menuitem_activate)
|
||||
self.handlers[id_] = configure_room_menuitem
|
||||
|
||||
id_ = destroy_room_menuitem.connect('activate',
|
||||
self._on_destroy_room_menuitem_activate)
|
||||
self.handlers[id_] = destroy_room_menuitem
|
||||
|
||||
id_ = change_subject_menuitem.connect('activate',
|
||||
self._on_change_subject_menuitem_activate)
|
||||
self.handlers[id_] = change_subject_menuitem
|
||||
|
||||
id_ = history_menuitem.connect('activate',
|
||||
self._on_history_menuitem_activate)
|
||||
self.handlers[id_] = history_menuitem
|
||||
|
||||
id_ = disconnect_menuitem.connect('activate',
|
||||
self._on_disconnect_menuitem_activate)
|
||||
self.handlers[id_] = disconnect_menuitem
|
||||
|
||||
id_ = request_voice_menuitem.connect('activate',
|
||||
self._on_request_voice_menuitem_activate)
|
||||
self.handlers[id_] = request_voice_menuitem
|
||||
|
||||
id_ = minimize_menuitem.connect('toggled',
|
||||
self.on_minimize_menuitem_toggled)
|
||||
self.handlers[id_] = minimize_menuitem
|
||||
|
||||
id_ = notify_menuitem.connect('toggled',
|
||||
self.on_notify_menuitem_toggled)
|
||||
self.handlers[id_] = notify_menuitem
|
||||
|
||||
menu.connect('selection-done', self.destroy_menu,
|
||||
change_nick_menuitem, change_subject_menuitem,
|
||||
bookmark_room_menuitem, history_menuitem)
|
||||
return menu
|
||||
|
||||
def destroy_menu(self, menu, change_nick_menuitem, change_subject_menuitem,
|
||||
bookmark_room_menuitem, history_menuitem):
|
||||
# destroy accelerators
|
||||
ag = Gtk.accel_groups_from_object(self.parent_win.window)[0]
|
||||
change_nick_menuitem.remove_accelerator(ag, Gdk.KEY_n,
|
||||
Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK)
|
||||
change_subject_menuitem.remove_accelerator(ag, Gdk.KEY_t,
|
||||
Gdk.ModifierType.MOD1_MASK)
|
||||
bookmark_room_menuitem.remove_accelerator(ag, Gdk.KEY_b,
|
||||
Gdk.ModifierType.CONTROL_MASK)
|
||||
history_menuitem.remove_accelerator(ag, Gdk.KEY_h,
|
||||
Gdk.ModifierType.CONTROL_MASK)
|
||||
# destroy menu
|
||||
menu.destroy()
|
||||
subject_text = '<span>%s</span>' % subject_text
|
||||
self.subject_button.get_popover().set_text(subject_text)
|
||||
|
||||
def _nec_vcard_published(self, obj):
|
||||
if obj.conn.name != self.account:
|
||||
|
@ -1379,6 +1358,11 @@ class GroupchatControl(ChatControlBase):
|
|||
else:
|
||||
self.print_conversation(text)
|
||||
|
||||
if obj.subject == '':
|
||||
self.subject_button.hide()
|
||||
else:
|
||||
self.subject_button.show()
|
||||
|
||||
def _nec_gc_config_changed_received(self, obj):
|
||||
# statuscode is a list
|
||||
# http://www.xmpp.org/extensions/xep-0045.html#roomconfig-notify
|
||||
|
@ -1467,18 +1451,12 @@ class GroupchatControl(ChatControlBase):
|
|||
|
||||
formattings_button = self.xml.get_object('formattings_button')
|
||||
formattings_button.set_sensitive(True)
|
||||
change_nick_button = self.xml.get_object('change_nick_button')
|
||||
change_nick_button.set_sensitive(True)
|
||||
change_subject_button = self.xml.get_object('change_subject_button')
|
||||
change_subject_button.set_sensitive(True)
|
||||
|
||||
self.update_actions()
|
||||
|
||||
def got_disconnected(self):
|
||||
formattings_button = self.xml.get_object('formattings_button')
|
||||
formattings_button.set_sensitive(False)
|
||||
change_nick_button = self.xml.get_object('change_nick_button')
|
||||
change_nick_button.set_sensitive(False)
|
||||
change_subject_button = self.xml.get_object('change_subject_button')
|
||||
change_subject_button.set_sensitive(False)
|
||||
self.list_treeview.set_model(None)
|
||||
self.model.clear()
|
||||
nick_list = app.contacts.get_nick_list(self.account, self.room_jid)
|
||||
|
@ -1512,6 +1490,8 @@ class GroupchatControl(ChatControlBase):
|
|||
if ar_to:
|
||||
self.autorejoin = GLib.timeout_add_seconds(ar_to, self.rejoin)
|
||||
|
||||
self.update_actions()
|
||||
|
||||
def rejoin(self):
|
||||
if not self.autorejoin:
|
||||
return False
|
||||
|
@ -1904,6 +1884,11 @@ class GroupchatControl(ChatControlBase):
|
|||
st += ' (' + obj.status + ')'
|
||||
self.print_conversation(st, graphics=False)
|
||||
|
||||
# Update Actions
|
||||
if obj.status_code:
|
||||
if '110' in obj.status_code:
|
||||
self.update_actions()
|
||||
|
||||
def add_contact_to_roster(self, nick, show, role, affiliation, status,
|
||||
jid='', avatar_sha=None):
|
||||
role_name = helpers.get_uf_role(role, plural=True)
|
||||
|
@ -2262,67 +2247,6 @@ class GroupchatControl(ChatControlBase):
|
|||
_('Please specify the new subject:'), input_str=self.subject,
|
||||
ok_handler=on_ok, transient_for=self.parent_win.window)
|
||||
|
||||
def _on_disconnect_menuitem_activate(self, widget):
|
||||
self.force_non_minimizable = True
|
||||
self.parent_win.remove_tab(self, self.parent_win.CLOSE_COMMAND)
|
||||
self.force_non_minimizable = False
|
||||
|
||||
def _on_change_nick_menuitem_activate(self, widget):
|
||||
if 'change_nick_dialog' in app.interface.instances:
|
||||
app.interface.instances['change_nick_dialog'].dialog.present()
|
||||
else:
|
||||
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,
|
||||
prompt, change_nick=True, transient_for=self.parent_win.window)
|
||||
|
||||
def _on_configure_room_menuitem_activate(self, widget):
|
||||
c = app.contacts.get_gc_contact(self.account, self.room_jid,
|
||||
self.nick)
|
||||
if c.affiliation == 'owner':
|
||||
app.connections[self.account].request_gc_config(self.room_jid)
|
||||
elif c.affiliation == 'admin':
|
||||
if self.room_jid not in app.interface.instances[self.account][
|
||||
'gc_config']:
|
||||
app.interface.instances[self.account]['gc_config'][
|
||||
self.room_jid] = config.GroupchatConfigWindow(self.account,
|
||||
self.room_jid)
|
||||
|
||||
def _on_destroy_room_menuitem_activate(self, widget):
|
||||
def on_ok(reason, jid):
|
||||
if jid:
|
||||
# Test jid
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
except Exception:
|
||||
dialogs.ErrorDialog(_('Invalid group chat JID'),
|
||||
_('The group chat JID has not allowed characters.'))
|
||||
return
|
||||
app.connections[self.account].destroy_gc_room(self.room_jid,
|
||||
reason, jid)
|
||||
|
||||
# Ask for a reason
|
||||
dialogs.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,
|
||||
transient_for=self.parent_win.window)
|
||||
|
||||
def _on_bookmark_room_menuitem_activate(self, widget):
|
||||
"""
|
||||
Bookmark the room, without autojoin and not minimized
|
||||
"""
|
||||
password = app.gc_passwords.get(self.room_jid, '')
|
||||
app.interface.add_gc_bookmark(self.account, self.name, self.room_jid,\
|
||||
'0', '0', password, self.nick)
|
||||
|
||||
def _on_request_voice_menuitem_activate(self, widget):
|
||||
"""
|
||||
Request voice in the current room
|
||||
"""
|
||||
app.connections[self.account].request_voice(self.room_jid)
|
||||
|
||||
def _on_drag_data_received(self, widget, context, x, y, selection,
|
||||
target_type, timestamp):
|
||||
# Invite contact to groupchat
|
||||
|
@ -2913,3 +2837,40 @@ class GroupchatControl(ChatControlBase):
|
|||
self.grant_owner(widget, jid)
|
||||
else:
|
||||
self.revoke_owner(widget, jid)
|
||||
|
||||
|
||||
class SubjectPopover(Gtk.Popover):
|
||||
def __init__(self):
|
||||
Gtk.Popover.__init__(self)
|
||||
self.set_name('SubjectPopover')
|
||||
|
||||
scrolledwindow = Gtk.ScrolledWindow()
|
||||
scrolledwindow.set_max_content_height(250)
|
||||
scrolledwindow.set_propagate_natural_height(True)
|
||||
scrolledwindow.set_propagate_natural_width(True)
|
||||
scrolledwindow.set_policy(Gtk.PolicyType.NEVER,
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
|
||||
self.label = Gtk.Label()
|
||||
self.label.set_line_wrap(True)
|
||||
self.label.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR)
|
||||
self.label.set_max_width_chars(80)
|
||||
|
||||
scrolledwindow.add(self.label)
|
||||
|
||||
box = Gtk.Box()
|
||||
box.add(scrolledwindow)
|
||||
box.show_all()
|
||||
self.add(box)
|
||||
|
||||
self.connect_after('show', self._after_show)
|
||||
|
||||
def set_text(self, text):
|
||||
self.label.set_markup(text)
|
||||
|
||||
def _after_show(self, *args):
|
||||
# Gtk Bug: If we set selectable True, on show
|
||||
# everything inside the Label is selected.
|
||||
# So we switch after show to False and again to True
|
||||
self.label.set_selectable(False)
|
||||
self.label.set_selectable(True)
|
||||
|
|
|
@ -57,6 +57,7 @@ class Color:
|
|||
BLACK = Gdk.RGBA(red=0, green=0, blue=0, alpha=1)
|
||||
GREEN = Gdk.RGBA(red=115/255, green=210/255, blue=22/255, alpha=1)
|
||||
RED = Gdk.RGBA(red=204/255, green=0, blue=0, alpha=1)
|
||||
GREY = Gdk.RGBA(red=195/255, green=195/255, blue=192/255, alpha=1)
|
||||
|
||||
def get_icon_pixmap(icon_name, size=16, color=None, quiet=False):
|
||||
try:
|
||||
|
|
|
@ -19,9 +19,17 @@
|
|||
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
import gi
|
||||
gi.require_version('GtkSpell', '3.0')
|
||||
from gi.repository import GtkSpell
|
||||
try:
|
||||
from gi.repository import GtkSpell
|
||||
HAS_GTK_SPELL = True
|
||||
except ImportError:
|
||||
HAS_GTK_SPELL = False
|
||||
|
||||
from gajim.common import app
|
||||
|
||||
|
||||
def ensure_attached(func):
|
||||
def f(self, *args, **kwargs):
|
||||
|
@ -47,12 +55,13 @@ class Spell(GObject.GObject):
|
|||
if spell:
|
||||
raise RuntimeError("Textview has already a Spell obj attached")
|
||||
self.spell = GtkSpell.Checker.new()
|
||||
if not self.spell:
|
||||
raise OSError("Unable to create spell object.")
|
||||
if not self.spell.attach(textview):
|
||||
raise OSError("Unable to attach spell object.")
|
||||
if not self.spell.set_language(language):
|
||||
raise OSError("Unable to set language: '%s'" % language)
|
||||
|
||||
try:
|
||||
self.spell.set_language(language)
|
||||
except GLib.GError as error:
|
||||
if error.domain == 'gtkspell-error-quark':
|
||||
raise OSError("Unable to set language: '%s'" % language)
|
||||
|
||||
self.spell.connect('language-changed', self.on_language_changed)
|
||||
|
||||
else:
|
||||
|
@ -73,12 +82,25 @@ class Spell(GObject.GObject):
|
|||
def recheck_all(self):
|
||||
self.spell.recheck_all()
|
||||
|
||||
@ensure_attached
|
||||
def detach(self):
|
||||
self.spell.detach()
|
||||
self.spell = None
|
||||
if self.spell is not None:
|
||||
self.spell.detach()
|
||||
|
||||
def attach(self, textview):
|
||||
spell = GtkSpell.Checker.get_from_text_view(textview)
|
||||
if spell is None:
|
||||
print('attached')
|
||||
self.spell.attach(textview)
|
||||
|
||||
|
||||
GObject.type_register(Spell)
|
||||
|
||||
def get_from_text_view(textview):
|
||||
return Spell(textview, create=False)
|
||||
|
||||
def test_language(lang):
|
||||
spell = GtkSpell.Checker.new()
|
||||
try:
|
||||
spell.set_language(lang)
|
||||
except GLib.GError as error:
|
||||
if error.domain == 'gtkspell-error-quark':
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -2858,18 +2858,6 @@ class Interface:
|
|||
# get transports type from DB
|
||||
app.transport_type = app.logger.get_transports_type()
|
||||
|
||||
# test is dictionnary is present for speller
|
||||
if app.config.get('use_speller'):
|
||||
lang = app.config.get('speller_language')
|
||||
if not lang:
|
||||
lang = app.LANG
|
||||
tv = Gtk.TextView()
|
||||
try:
|
||||
from gajim import gtkspell
|
||||
spell = gtkspell.Spell(tv, lang)
|
||||
except (ImportError, TypeError, RuntimeError, OSError, ValueError):
|
||||
dialogs.AspellDictError(lang)
|
||||
|
||||
if app.config.get('soundplayer') == '':
|
||||
# only on first time Gajim starts
|
||||
commands = ('paplay', 'aplay', 'play', 'ossplay')
|
||||
|
|
|
@ -606,6 +606,65 @@ Build dynamic Application Menus
|
|||
'''
|
||||
|
||||
|
||||
def get_singlechat_menu(control_id):
|
||||
singlechat_menu = [
|
||||
('win.send-file-', _('Send File...')),
|
||||
('win.invite-contacts-', _('Invite Contacts')),
|
||||
('win.add-to-roster-', _('Add to Roster')),
|
||||
('win.toggle-audio-', _('Audio Session')),
|
||||
('win.toggle-video-', _('Video Session')),
|
||||
('win.information-', _('Information')),
|
||||
('win.browse-history-', _('History')),
|
||||
]
|
||||
|
||||
def build_menu(preset):
|
||||
menu = Gio.Menu()
|
||||
for item in preset:
|
||||
action_name, label = item
|
||||
if action_name == 'win.browse-history-':
|
||||
menu.append(label, action_name + control_id + '::none')
|
||||
else:
|
||||
menu.append(label, action_name + control_id)
|
||||
return menu
|
||||
|
||||
return build_menu(singlechat_menu)
|
||||
|
||||
|
||||
def get_groupchat_menu(control_id):
|
||||
groupchat_menu = [
|
||||
(_('Manage Room'), [
|
||||
('win.change-subject-', _('Change Subject')),
|
||||
('win.configure-', _('Configure Room')),
|
||||
('win.destroy-', _('Destroy Room')),
|
||||
]),
|
||||
('win.change-nick-', _('Change Nick')),
|
||||
('win.bookmark-', _('Bookmark Room')),
|
||||
('win.request-voice-', _('Request Voice')),
|
||||
('win.notify-on-message-', _('Notify on all messages')),
|
||||
('win.minimize-', _('Minimize on close')),
|
||||
('win.browse-history-', _('History')),
|
||||
('win.disconnect-', _('Disconnect')),
|
||||
]
|
||||
|
||||
def build_menu(preset):
|
||||
menu = Gio.Menu()
|
||||
for item in preset:
|
||||
if isinstance(item[1], str):
|
||||
action_name, label = item
|
||||
if action_name == 'win.browse-history-':
|
||||
menu.append(label, action_name + control_id + '::none')
|
||||
else:
|
||||
menu.append(label, action_name + control_id)
|
||||
else:
|
||||
label, sub_menu = item
|
||||
# This is a submenu
|
||||
submenu = build_menu(sub_menu)
|
||||
menu.append_submenu(label, submenu)
|
||||
return menu
|
||||
|
||||
return build_menu(groupchat_menu)
|
||||
|
||||
|
||||
def get_bookmarks_menu(account, rebuild=False):
|
||||
if not app.connections[account].bookmarks:
|
||||
return None
|
||||
|
@ -708,7 +767,11 @@ def get_account_menu(account):
|
|||
def build_accounts_menu():
|
||||
menubar = app.app.get_menubar()
|
||||
# Accounts Submenu
|
||||
acc_menu = menubar.get_item_link(0, 'submenu')
|
||||
menu_position = 0
|
||||
if os.name == 'nt':
|
||||
menu_position = 1
|
||||
|
||||
acc_menu = menubar.get_item_link(menu_position, 'submenu')
|
||||
acc_menu.remove_all()
|
||||
accounts_list = sorted(app.contacts.get_accounts())
|
||||
if not accounts_list:
|
||||
|
@ -721,8 +784,8 @@ def build_accounts_menu():
|
|||
acc, get_account_menu(acc))
|
||||
else:
|
||||
acc_menu = get_account_menu(accounts_list[0])
|
||||
menubar.remove(0)
|
||||
menubar.insert_submenu(0, 'Accounts', acc_menu)
|
||||
menubar.remove(menu_position)
|
||||
menubar.insert_submenu(menu_position, 'Accounts', acc_menu)
|
||||
|
||||
|
||||
def build_bookmark_menu(account):
|
||||
|
@ -731,8 +794,12 @@ def build_bookmark_menu(account):
|
|||
if not bookmark_menu:
|
||||
return
|
||||
|
||||
menu_position = 0
|
||||
if os.name == 'nt':
|
||||
menu_position = 1
|
||||
|
||||
# Accounts Submenu
|
||||
acc_menu = menubar.get_item_link(0, 'submenu')
|
||||
acc_menu = menubar.get_item_link(menu_position, 'submenu')
|
||||
|
||||
# We have more than one Account active
|
||||
if acc_menu.get_item_link(0, 'submenu'):
|
||||
|
|
|
@ -57,7 +57,6 @@ class MessageControl(object):
|
|||
self.widget_name = widget_name
|
||||
self.contact = contact
|
||||
self.account = account
|
||||
self.hide_chat_buttons = False
|
||||
self.resource = resource
|
||||
# control_id is a unique id for the control,
|
||||
# its used as action name for actions that belong to a control
|
||||
|
@ -175,12 +174,6 @@ class MessageControl(object):
|
|||
"""
|
||||
return None
|
||||
|
||||
def chat_buttons_set_visible(self, state):
|
||||
"""
|
||||
Derived classes MAY implement this
|
||||
"""
|
||||
self.hide_chat_buttons = state
|
||||
|
||||
def got_connected(self):
|
||||
pass
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
import gc
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Pango
|
||||
|
||||
|
@ -37,6 +36,7 @@ class MessageTextView(Gtk.TextView):
|
|||
chat/groupchat windows
|
||||
"""
|
||||
UNDO_LIMIT = 20
|
||||
PLACEHOLDER = _('Write a message..')
|
||||
|
||||
def __init__(self):
|
||||
Gtk.TextView.__init__(self)
|
||||
|
@ -57,13 +57,16 @@ class MessageTextView(Gtk.TextView):
|
|||
self.undo_list = []
|
||||
# needed to know if we undid something
|
||||
self.undo_pressed = False
|
||||
self.lang = None # Lang used for spell checking
|
||||
|
||||
_buffer = self.get_buffer()
|
||||
self.begin_tags = {}
|
||||
self.end_tags = {}
|
||||
self.color_tags = []
|
||||
self.fonts_tags = []
|
||||
self.other_tags = {}
|
||||
self.placeholder_tag = _buffer.create_tag('placeholder')
|
||||
self.placeholder_tag.set_property('foreground_rgba',
|
||||
gtkgui_helpers.Color.GREY)
|
||||
self.other_tags['bold'] = _buffer.create_tag('bold')
|
||||
self.other_tags['bold'].set_property('weight', Pango.Weight.BOLD)
|
||||
self.begin_tags['bold'] = '<strong>'
|
||||
|
@ -82,6 +85,33 @@ class MessageTextView(Gtk.TextView):
|
|||
self.end_tags['strike'] = '</span>'
|
||||
|
||||
self.connect_after('paste-clipboard', self.after_paste_clipboard)
|
||||
self.connect('focus-in-event', self._on_focus_in)
|
||||
self.connect('focus-out-event', self._on_focus_out)
|
||||
|
||||
start, end = _buffer.get_bounds()
|
||||
_buffer.insert_with_tags(
|
||||
start, self.PLACEHOLDER, self.placeholder_tag)
|
||||
|
||||
def has_text(self):
|
||||
buf = self.get_buffer()
|
||||
start, end = buf.get_bounds()
|
||||
text = buf.get_text(start, end, True)
|
||||
return text != self.PLACEHOLDER
|
||||
|
||||
def _on_focus_in(self, *args):
|
||||
if not self.has_text():
|
||||
self.get_buffer().set_text('')
|
||||
|
||||
def _on_focus_out(self, *args):
|
||||
buf = self.get_buffer()
|
||||
start, end = buf.get_bounds()
|
||||
text = buf.get_text(start, end, True)
|
||||
if text == '':
|
||||
buf.insert_with_tags(
|
||||
start, self.PLACEHOLDER, self.placeholder_tag)
|
||||
|
||||
def remove_placeholder(self):
|
||||
self._on_focus_in()
|
||||
|
||||
def after_paste_clipboard(self, textview):
|
||||
buffer_ = textview.get_buffer()
|
||||
|
|
|
@ -81,7 +81,6 @@ class MessageWindow(object):
|
|||
self.xml = gtkgui_helpers.get_gtk_builder('%s.ui' % self.widget_name)
|
||||
self.window = self.xml.get_object(self.widget_name)
|
||||
self.window.set_application(app.app)
|
||||
self.window.set_show_menubar(False)
|
||||
self.notebook = self.xml.get_object('notebook')
|
||||
self.parent_paned = None
|
||||
|
||||
|
@ -94,17 +93,26 @@ class MessageWindow(object):
|
|||
if app.config.get('roster_on_the_right'):
|
||||
child1 = self.parent_paned.get_child1()
|
||||
self.parent_paned.remove(child1)
|
||||
self.parent_paned.add(self.notebook)
|
||||
self.parent_paned.pack1(self.notebook, resize=False,
|
||||
shrink=True)
|
||||
self.parent_paned.pack2(child1, resize=True, shrink=True)
|
||||
self.parent_paned.pack1(self.notebook, resize=False)
|
||||
self.parent_paned.pack2(child1)
|
||||
else:
|
||||
self.parent_paned.add(self.notebook)
|
||||
self.parent_paned.pack2(self.notebook, resize=True, shrink=True)
|
||||
self.parent_paned.pack2(self.notebook)
|
||||
self.window.lookup_action('show-roster').set_enabled(True)
|
||||
orig_window.destroy()
|
||||
del orig_window
|
||||
|
||||
# Set headermenu
|
||||
# single-window mode: show the header menu on the roster window
|
||||
# all other modes: add the headerbar to the new window
|
||||
# A headerbar has to be set before the window calls show()
|
||||
if parent_window:
|
||||
self.header_menu = app.interface.roster.header_menu
|
||||
self.header_menu.show()
|
||||
else:
|
||||
self.header_menu = self.xml.get_object('header_menu')
|
||||
headerbar = self.xml.get_object('headerbar')
|
||||
self.window.set_titlebar(headerbar)
|
||||
|
||||
# NOTE: we use 'connect_after' here because in
|
||||
# MessageWindowMgr._new_window we register handler that saves window
|
||||
# state when closing it, and it should be called before
|
||||
|
@ -162,6 +170,9 @@ class MessageWindow(object):
|
|||
self.notebook.set_show_border(app.config.get('tabs_border'))
|
||||
self.show_icon()
|
||||
|
||||
def set_header_menu(self, menu):
|
||||
self.header_menu.set_menu_model(menu)
|
||||
|
||||
def change_account_name(self, old_name, new_name):
|
||||
if old_name in self._controls:
|
||||
self._controls[new_name] = self._controls[old_name]
|
||||
|
@ -324,6 +335,7 @@ class MessageWindow(object):
|
|||
self.notebook.show_all()
|
||||
else:
|
||||
self.window.show_all()
|
||||
|
||||
# NOTE: we do not call set_control_active(True) since we don't know
|
||||
# whether the tab is the active one.
|
||||
self.show_title()
|
||||
|
@ -436,9 +448,6 @@ class MessageWindow(object):
|
|||
elif chr(keyval) in st: # ALT + 1,2,3..
|
||||
self.notebook.set_current_page(st.index(chr(keyval)))
|
||||
return True
|
||||
elif keyval == Gdk.KEY_c: # ALT + C toggles chat buttons
|
||||
control.chat_buttons_set_visible(not control.hide_chat_buttons)
|
||||
return True
|
||||
elif keyval == Gdk.KEY_m: # ALT + M show emoticons menu
|
||||
control.emoticons_button.get_popover().show()
|
||||
return True
|
||||
|
@ -570,6 +579,7 @@ class MessageWindow(object):
|
|||
ask any confirmation
|
||||
"""
|
||||
def close(ctrl):
|
||||
self.remove_headermenu(self.notebook, ctrl)
|
||||
if reason is not None: # We are leaving gc with a status message
|
||||
ctrl.shutdown(reason)
|
||||
else: # We are leaving gc without status message or it's a chat
|
||||
|
@ -607,6 +617,7 @@ class MessageWindow(object):
|
|||
|
||||
def on_minimize(ctrl):
|
||||
if method != self.CLOSE_COMMAND:
|
||||
self.remove_headermenu(self.notebook, ctrl)
|
||||
ctrl.minimize()
|
||||
self.check_tabs()
|
||||
return
|
||||
|
@ -618,6 +629,13 @@ class MessageWindow(object):
|
|||
else:
|
||||
ctrl.allow_shutdown(method, on_yes, on_no, on_minimize)
|
||||
|
||||
def remove_headermenu(self, notebook, ctrl):
|
||||
page_num = notebook.page_num(ctrl.widget)
|
||||
if page_num == notebook.get_current_page():
|
||||
self.set_header_menu(None)
|
||||
elif notebook.get_n_pages() == 1:
|
||||
self.set_header_menu(None)
|
||||
|
||||
def check_tabs(self):
|
||||
if self.parent_paned:
|
||||
# Do nothing in single window mode
|
||||
|
@ -822,6 +840,8 @@ class MessageWindow(object):
|
|||
|
||||
def popup_menu(self, event):
|
||||
menu = self.get_active_control().prepare_context_menu()
|
||||
if menu is None:
|
||||
return
|
||||
# show the menu
|
||||
menu.attach_to_widget(app.interface.roster.window, None)
|
||||
menu.show_all()
|
||||
|
@ -836,6 +856,7 @@ class MessageWindow(object):
|
|||
new_ctrl = self._widget_to_control(notebook.get_nth_page(page_num))
|
||||
new_ctrl.set_control_active(True)
|
||||
self.show_title(control = new_ctrl)
|
||||
self.set_header_menu(new_ctrl.control_menu)
|
||||
|
||||
control = self.get_active_control()
|
||||
if isinstance(control, ChatControlBase):
|
||||
|
@ -879,6 +900,7 @@ class MessageWindow(object):
|
|||
|
||||
if isinstance(control, ChatControlBase):
|
||||
# we forwarded it to message textview
|
||||
control.msg_textview.remove_placeholder()
|
||||
control.msg_textview.event(event)
|
||||
control.msg_textview.grab_focus()
|
||||
|
||||
|
@ -1289,6 +1311,7 @@ class MessageWindowMgr(GObject.GObject):
|
|||
gtkgui_helpers.resize_window(w.window,
|
||||
app.config.get('roster_width'),
|
||||
app.config.get('roster_height'))
|
||||
self.hide_header_bar(self.parent_win)
|
||||
|
||||
self._windows = {}
|
||||
|
||||
|
@ -1298,8 +1321,16 @@ class MessageWindowMgr(GObject.GObject):
|
|||
mw = self.create_window(ctrl.contact, ctrl.account,
|
||||
ctrl.type_id)
|
||||
ctrl.parent_win = mw
|
||||
ctrl.add_actions()
|
||||
ctrl.update_actions()
|
||||
mw.new_tab(ctrl)
|
||||
|
||||
@staticmethod
|
||||
def hide_header_bar(parent_win):
|
||||
header_bar = parent_win.get_titlebar()
|
||||
for child in header_bar.get_children():
|
||||
child.hide()
|
||||
|
||||
def save_opened_controls(self):
|
||||
if not app.config.get('remember_opened_chat_controls'):
|
||||
return
|
||||
|
|
|
@ -5696,9 +5696,18 @@ class RosterWindow:
|
|||
application.add_window(self.window)
|
||||
self.add_actions()
|
||||
self.hpaned = self.xml.get_object('roster_hpaned')
|
||||
|
||||
app.interface.msg_win_mgr = MessageWindowMgr(self.window, self.hpaned)
|
||||
app.interface.msg_win_mgr.connect('window-delete',
|
||||
self.on_message_window_delete)
|
||||
|
||||
# Set headermenu but hide it.
|
||||
# MessageWindow will show it if we are in single-window mode
|
||||
headerbar = self.xml.get_object('headerbar')
|
||||
self.window.set_titlebar(headerbar)
|
||||
self.header_menu = self.xml.get_object('header_menu')
|
||||
self.header_menu.hide()
|
||||
|
||||
self.advanced_menus = [] # We keep them to destroy them
|
||||
if app.config.get('roster_window_skip_taskbar'):
|
||||
self.window.set_property('skip-taskbar-hint', True)
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
# -*- coding:utf-8 -*-
|
||||
# Copyright (C) 2015 Patrick Griffis <tingping@tingping.se>
|
||||
# Copyright (C) 2014 Christian Hergert <christian@hergert.me>
|
||||
#
|
||||
# This program 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.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
# MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from gi.repository import GObject, Gtk
|
||||
|
||||
class ScrolledWindow(Gtk.ScrolledWindow):
|
||||
"""
|
||||
ScrolledWindow that sets a max size for the child to grow into.
|
||||
Taken from the Gnome Builder project:
|
||||
https://git.gnome.org/browse/gnome-builder/tree/contrib/egg/egg-scrolled-window.c
|
||||
"""
|
||||
__gtype_name__ = "EggScrolledWindow"
|
||||
|
||||
max_content_height = GObject.Property(type=int, default=-1, nick="Max Content Height",
|
||||
blurb="The maximum height request that can be made")
|
||||
max_content_width = GObject.Property(type=int, default=-1, nick="Max Content Width",
|
||||
blurb="The maximum width request that can be made")
|
||||
min_content_height = GObject.Property(type=int, default=-1, nick="Min Content Height",
|
||||
blurb="The minimum height request that can be made")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.connect_after("notify::max-content-height", lambda obj, param: self.queue_resize())
|
||||
self.connect_after("notify::max-content-width", lambda obj, param: self.queue_resize())
|
||||
|
||||
def set_min_content_height(self, value):
|
||||
self.min_content_height = value
|
||||
|
||||
def set_max_content_height(self, value):
|
||||
self.max_content_height = value
|
||||
|
||||
def set_max_content_width(self, value):
|
||||
self.max_content_width = value
|
||||
|
||||
def get_max_content_height(self):
|
||||
return self.max_content_height
|
||||
|
||||
def get_max_content_width(self):
|
||||
return self.max_content_width
|
||||
|
||||
def do_get_preferred_height(self):
|
||||
min_height, natural_height = Gtk.ScrolledWindow.do_get_preferred_height(self)
|
||||
child = self.get_child()
|
||||
|
||||
if natural_height and self.max_content_height > -1 and child:
|
||||
|
||||
style = self.get_style_context()
|
||||
border = style.get_border(style.get_state())
|
||||
additional = border.top + border.bottom
|
||||
|
||||
child_min_height, child_nat_height = child.get_preferred_height()
|
||||
if child_nat_height > natural_height and self.max_content_height > natural_height:
|
||||
natural_height = min(self.max_content_height, child_nat_height) + additional
|
||||
elif natural_height > child_nat_height:
|
||||
if child_nat_height < self.min_content_height:
|
||||
return self.min_content_height, self.min_content_height
|
||||
min_height, natural_height = child_min_height + additional, child_nat_height + additional
|
||||
|
||||
return min_height, natural_height
|
||||
|
||||
def do_get_preferred_width(self):
|
||||
min_width, natural_width = Gtk.ScrolledWindow.do_get_preferred_width(self)
|
||||
child = self.get_child()
|
||||
|
||||
if natural_width and self.max_content_width > -1 and child:
|
||||
|
||||
style = self.get_style_context()
|
||||
border = style.get_border(style.get_state())
|
||||
additional = border.left + border.right + 1
|
||||
|
||||
child_min_width, child_nat_width = child.get_preferred_width()
|
||||
if child_nat_width > natural_width and self.max_content_width > natural_width:
|
||||
natural_width = min(self.max_content_width, child_nat_width) + additional
|
||||
|
||||
return min_width, natural_width
|
Loading…
Reference in New Issue