def _delete_jid_logs(self, liststore, list_of_paths): paths_len = len(list_of_paths) if paths_len == 0: # nothing is selected return def on_ok(): # delete all rows from db that match jid_id list_of_rowrefs = [] for path in list_of_paths: # make them treerowrefs (it's needed) list_of_rowrefs.append( Gtk.TreeRowReference.new(liststore, path)) for rowref in list_of_rowrefs: path = rowref.get_path() if path is None: continue jid_id = liststore[path][1] del liststore[path] # remove from UI # remove from db self.cur.execute( ''' DELETE FROM logs WHERE jid_id = ? ''', (jid_id, )) # now delete "jid, jid_id" row from jids table self.cur.execute( ''' DELETE FROM jids WHERE jid_id = ? ''', (jid_id, )) self.con.commit() self.AT_LEAST_ONE_DELETION_DONE = True NewConfirmationDialog( _('Delete'), ngettext('Delete Conversation', 'Delete Conversations', paths_len), ngettext( 'Do you want to permanently delete this ' 'conversation with <b>%s</b>?', 'Do you want to permanently delete these conversations?', paths_len, liststore[list_of_paths[0]][0]), [ DialogButton.make('Cancel'), DialogButton.make('Delete', callback=on_ok) ], transient_for=self._ui.history_manager_window).show()
def handle_incoming_gc_msg_event(self, msg_obj): if not msg_obj.gc_control: # we got a message from a room we're not in? ignore it return self.jid = msg_obj.jid sound = msg_obj.gc_control.highlighting_for_message( msg_obj.msgtxt, msg_obj.timestamp)[1] if msg_obj.nickname != msg_obj.gc_control.nick: self.do_sound = True if sound == 'received': self.sound_event = 'muc_message_received' elif sound == 'highlight': self.sound_event = 'muc_message_highlight' else: self.do_sound = False else: self.do_sound = False self.control = app.interface.msg_win_mgr.search_control( msg_obj.jid, self.account) if self.control is not None: self.control_focused = self.control.has_focus() if app.config.get('notify_on_new_message'): notify_for_muc = (app.config.notify_for_muc(self.jid) or sound == 'highlight') if not notify_for_muc: self.do_popup = False elif self.control_focused: self.do_popup = False elif app.config.get('autopopupaway'): # always show notification self.do_popup = True elif app.connections[self.conn.name].connected in (2, 3): # we're online or chat self.do_popup = True self.popup_msg_type = 'gc_msg' self.popup_event_type = _('New Group Chat Message') if app.config.get('notification_preview_message'): self.popup_text = msg_obj.msgtxt type_events = ['printed_marked_gc_msg', 'printed_gc_msg'] count = len(app.events.get_events(self.account, self.jid, type_events)) contact = app.contacts.get_contact(self.account, self.jid) self.popup_title = i18n.ngettext( 'New message from %(nickname)s', '%(n_msgs)i unread messages in %(groupchat_name)s', count) % { 'nickname': msg_obj.nick, 'n_msgs': count, 'groupchat_name': contact.get_shown_name() }
def build_sync_menu(): menu = Gio.Menu() days = app.config.get('threshold_options').split(',') days = [int(day) for day in days] action_name = 'win.choose-sync-%s::' % control_id for day in days: if day == 0: label = _('No threshold') else: label = ngettext('%i day', '%i days', day, day, day) menu.append(label, '%s%s' % (action_name, day)) return menu
def _delete_logs(self, liststore, list_of_paths): paths_len = len(list_of_paths) if paths_len == 0: # nothing is selected return def on_ok(): # delete rows from db that match log_line_id list_of_rowrefs = [] for path in list_of_paths: # make them treerowrefs (it's needed) list_of_rowrefs.append( Gtk.TreeRowReference.new(liststore, path)) for rowref in list_of_rowrefs: path = rowref.get_path() if path is None: continue log_line_id = liststore[path][0] del liststore[path] # remove from UI # remove from db self.cur.execute( ''' DELETE FROM logs WHERE log_line_id = ? ''', (log_line_id, )) self.con.commit() self.AT_LEAST_ONE_DELETION_DONE = True NewConfirmationDialog( _('Delete'), ngettext('Delete Message', 'Delete Messages', paths_len), ngettext('Do you want to permanently delete this message', 'Do you want to permanently delete these messages', paths_len), [ DialogButton.make('Cancel'), DialogButton.make('Delete', callback=on_ok) ], transient_for=self._ui.history_manager_window).show()
def updateCounter(self): """ Display number of events on the top of window, sometimes it needs to be changed """ count = len(self.__class__.entries) if count: self.new_entry_label.set_text(i18n.ngettext( 'You have received new entries (and %d not displayed):', 'You have received new entries (and %d not displayed):', count, count, count)) self.next_button.set_sensitive(True) else: self.new_entry_label.set_text(_('You have received new entry:')) self.next_button.set_sensitive(False)
def _delete_logs(self, liststore, list_of_paths): paths_len = len(list_of_paths) if paths_len == 0: # nothing is selected return def on_ok(liststore, list_of_paths): # delete rows from db that match log_line_id list_of_rowrefs = [] for path in list_of_paths: # make them treerowrefs (it's needed) list_of_rowrefs.append( Gtk.TreeRowReference.new(liststore, path)) for rowref in list_of_rowrefs: path = rowref.get_path() if path is None: continue log_line_id = liststore[path][0] del liststore[path] # remove from UI # remove from db self.cur.execute( ''' DELETE FROM logs WHERE log_line_id = ? ''', (log_line_id, )) self.con.commit() self.AT_LEAST_ONE_DELETION_DONE = True pri_text = i18n.ngettext( 'Do you really want to delete the selected message?', 'Do you really want to delete the selected messages?', paths_len) dialog = dialogs.ConfirmationDialog( pri_text, _('This is an irreversible operation.'), on_response_ok=(on_ok, liststore, list_of_paths)) dialog.set_title(_('Deletion Confirmation')) ok_button = dialog.get_children()[0].get_children()[1].get_children( )[0] ok_button.grab_focus() dialog.set_transient_for(self.window)
def handle_incoming_msg_event(self, msg_obj): # don't alert for carbon copied messages from ourselves if msg_obj.sent: return if not msg_obj.msgtxt: return self.jid = msg_obj.jid if msg_obj.mtype == 'pm': self.jid = msg_obj.fjid self.control = app.interface.msg_win_mgr.search_control( msg_obj.jid, self.account, msg_obj.resource) if self.control is None: if len(app.events.get_events( self.account, msg_obj.jid, [msg_obj.mtype])) <= 1: self.first_unread = True else: self.control_focused = self.control.has_focus() if msg_obj.mtype == 'pm': nick = msg_obj.resource else: nick = app.get_name_from_jid(self.conn.name, self.jid) if self.first_unread: self.sound_event = 'first_message_received' elif self.control_focused: self.sound_event = 'next_message_received_focused' else: self.sound_event = 'next_message_received_unfocused' if app.config.get('notification_preview_message'): self.popup_text = msg_obj.msgtxt if self.popup_text and (self.popup_text.startswith('/me ') or \ self.popup_text.startswith('/me\n')): self.popup_text = '* ' + nick + self.popup_text[3:] else: # We don't want message preview, do_preview = False self.popup_text = '' if msg_obj.mtype == 'normal': # single message self.popup_msg_type = 'normal' self.popup_event_type = _('New Single Message') elif msg_obj.mtype == 'pm': self.popup_msg_type = 'pm' self.popup_event_type = _('New Private Message') else: # chat message self.popup_msg_type = 'chat' self.popup_event_type = _('New Message') num_unread = len(app.events.get_events(self.conn.name, self.jid, ['printed_' + self.popup_msg_type, self.popup_msg_type])) self.popup_title = i18n.ngettext( 'New message from %(nickname)s', '%(n_msgs)i unread messages from %(nickname)s', num_unread) % {'nickname': nick, 'n_msgs': num_unread} if app.config.get('notify_on_new_message'): if self.first_unread or (app.config.get('autopopup_chat_opened') \ and not self.control_focused): if app.config.get('autopopupaway'): # always show notification self.do_popup = True if app.connections[self.conn.name].connected in (2, 3): # we're online or chat self.do_popup = True if msg_obj.attention and not app.config.get( 'ignore_incoming_attention'): self.popup_timeout = 0 self.do_popup = True else: self.popup_timeout = app.config.get('notification_timeout') if msg_obj.attention and not app.config.get( 'ignore_incoming_attention') and app.config.get_per('soundevents', 'attention_received', 'enabled'): self.sound_event = 'attention_received' self.do_sound = True elif self.first_unread and helpers.allow_sound_notification( self.conn.name, 'first_message_received'): self.do_sound = True elif not self.first_unread and self.control_focused and \ helpers.allow_sound_notification(self.conn.name, 'next_message_received_focused'): self.do_sound = True elif not self.first_unread and not self.control_focused and \ helpers.allow_sound_notification(self.conn.name, 'next_message_received_unfocused'): self.do_sound = True
def get_notification_icon_tooltip_dict(): """ Return a dict of the form {acct: {'show': show, 'message': message, 'event_lines': [list of text lines to show in tooltip]} """ # How many events before we show summarized, not per-user max_ungrouped_events = 10 accounts = get_accounts_info() # Gather events. (With accounts, when there are more.) for account in accounts: account_name = account['name'] account['event_lines'] = [] # Gather events per-account pending_events = app.events.get_events(account=account_name) messages, non_messages = {}, {} total_messages, total_non_messages = 0, 0 for jid in pending_events: for event in pending_events[jid]: if event.type_.count('file') > 0: # This is a non-messagee event. messages[jid] = non_messages.get(jid, 0) + 1 total_non_messages = total_non_messages + 1 else: # This is a message. messages[jid] = messages.get(jid, 0) + 1 total_messages = total_messages + 1 # Display unread messages numbers, if any if total_messages > 0: if total_messages > max_ungrouped_events: text = ngettext('%d message pending', '%d messages pending', total_messages, total_messages, total_messages) account['event_lines'].append(text) else: for jid in messages: text = ngettext('%d message pending', '%d messages pending', messages[jid], messages[jid], messages[jid]) contact = app.contacts.get_first_contact_from_jid( account['name'], jid) text += ' ' if jid in app.gc_connected[account['name']]: text += _('from group chat %s') % (jid) elif contact: name = contact.get_shown_name() text += _('from user %s') % (name) else: text += _('from %s') % (jid) account['event_lines'].append(text) # Display unseen events numbers, if any if total_non_messages > 0: if total_non_messages > max_ungrouped_events: text = ngettext('%d event pending', '%d events pending', total_non_messages, total_non_messages, total_non_messages) account['event_lines'].append(text) else: for jid in non_messages: text = ngettext('%d event pending', '%d events pending', non_messages[jid], non_messages[jid], non_messages[jid]) text += ' ' + _('from user %s') % (jid) account[account]['event_lines'].append(text) return accounts
def handle_incoming_gc_msg_event(self, msg_obj): if not msg_obj.gc_control: # we got a message from a room we're not in? ignore it return self.jid = msg_obj.jid sound = msg_obj.gc_control.highlighting_for_message( msg_obj.msgtxt, msg_obj.properties.timestamp)[1] nick = msg_obj.properties.muc_nickname if nick == msg_obj.gc_control.nick: # A message from ourself return self.do_sound = True if sound == 'received': self.sound_event = 'muc_message_received' elif sound == 'highlight': self.sound_event = 'muc_message_highlight' else: self.do_sound = False self.control = app.interface.msg_win_mgr.search_control( msg_obj.jid, self.account) if self.control is not None: self.control_focused = self.control.has_focus() if app.settings.get('show_notifications'): contact = app.contacts.get_groupchat_contact(self.account, self.jid) notify_for_muc = sound == 'highlight' or contact.can_notify() if not notify_for_muc: self.do_popup = False elif self.control_focused: self.do_popup = False elif app.settings.get('autopopupaway'): # always show notification self.do_popup = True elif app.connections[self.conn.name].status in ('online', 'chat'): # we're online or chat self.do_popup = True self.popup_msg_type = 'gc_msg' self.popup_event_type = _('New Group Chat Message') if app.settings.get('notification_preview_message'): self.popup_text = msg_obj.msgtxt if self.popup_text and (self.popup_text.startswith('/me ') or self.popup_text.startswith('/me\n')): self.popup_text = '* ' + nick + self.popup_text[3:] type_events = ['printed_marked_gc_msg', 'printed_gc_msg'] count = len(app.events.get_events(self.account, self.jid, type_events)) contact = app.contacts.get_contact(self.account, self.jid) self.popup_title = i18n.ngettext( 'New message from %(nickname)s', '%(n_msgs)i unread messages in %(groupchat_name)s', count) % {'nickname': nick, 'n_msgs': count, 'groupchat_name': contact.get_shown_name()}
def __init__(self): Gtk.ApplicationWindow.__init__(self) self.set_application(app.app) self.set_position(Gtk.WindowPosition.CENTER) self.set_show_menubar(False) self.set_title(_('Preferences')) self._ui = get_builder('preferences_window.ui') self.add(self._ui.preferences_window) ### General tab ### ## Behavior of Windows and Tabs # Set default for single window type choices = c_config.opt_one_window_types type_ = app.config.get('one_message_window') if type_ in choices: self._ui.one_window_type_combobox.set_active(choices.index(type_)) else: self._ui.one_window_type_combobox.set_active(0) # Show roster on startup choices = c_config.opt_show_roster_on_startup type_ = app.config.get('show_roster_on_startup') if type_ in choices: self._ui.show_roster_on_startup.set_active(choices.index(type_)) else: self._ui.show_roster_on_startup.set_active(0) # Quit on roster x st = app.config.get('quit_on_roster_x_button') self._ui.quit_on_roster_x_checkbutton.set_active(st) # Tab placement st = app.config.get('tabs_position') if st == 'top': self._ui.tabs_placement.set_active(0) elif st == 'bottom': self._ui.tabs_placement.set_active(1) elif st == 'left': self._ui.tabs_placement.set_active(2) else: # right self._ui.tabs_placement.set_active(3) # Show avatar in tabs st = app.config.get('show_avatar_in_tabs') self._ui.show_avatar_in_tabs_checkbutton.set_active(st) ## Contact List Appearance # Display avatars in roster st = app.config.get('show_avatars_in_roster') self._ui.show_avatars_in_roster_checkbutton.set_active(st) # Display status msg under contact name in roster st = app.config.get('show_status_msgs_in_roster') self._ui.show_status_msgs_in_roster_checkbutton.set_active(st) # Display PEP in roster st1 = app.config.get('show_mood_in_roster') st2 = app.config.get('show_activity_in_roster') st3 = app.config.get('show_tunes_in_roster') st4 = app.config.get('show_location_in_roster') if st1 == st2 == st3 == st4: self._ui.show_pep_in_roster_checkbutton.set_active(st1) else: self._ui.show_pep_in_roster_checkbutton.set_inconsistent(True) # Sort contacts by show st = app.config.get('sort_by_show_in_roster') self._ui.sort_by_show_in_roster_checkbutton.set_active(st) st = app.config.get('sort_by_show_in_muc') self._ui.sort_by_show_in_muc_checkbutton.set_active(st) ### Chat tab ### ## Chat Settings # Use speller if app.is_installed('GSPELL'): st = app.config.get('use_speller') self._ui.speller_checkbutton.set_active(st) else: self._ui.speller_checkbutton.set_sensitive(False) # XEP-0184 positive ack st = app.config.get('positive_184_ack') self._ui.positive_184_ack_checkbutton.set_active(st) # Ignore XHTML st = app.config.get('ignore_incoming_xhtml') self._ui.xhtml_checkbutton.set_active(st) # Print status messages in single chats st = app.config.get('print_status_in_chats') self._ui.print_status_in_chats_checkbutton.set_active(st) # Show subject on join st = app.config.get('show_subject_on_join') self._ui.subject_on_join_checkbutton.set_active(st) # Group chat settings threshold_model = self._ui.sync_threshold_combobox.get_model() days = app.config.get_options('threshold_options', return_type=int) for day in days: if day == 0: label = _('No threshold') else: label = ngettext('%i day', '%i days', day, day, day) threshold_model.append([str(day), label]) public_threshold = app.config.get('public_room_sync_threshold') self._ui.sync_threshold_combobox.set_id_column(0) self._ui.sync_threshold_combobox.set_active_id(str(public_threshold)) st = app.config.get('print_join_left_default') self._ui.join_leave_checkbutton.set_active(st) st = app.config.get('print_status_muc_default') self._ui.status_change_checkbutton.set_active(st) # Displayed chat state notifications st = app.config.get('show_chatstate_in_tabs') self._ui.show_chatstate_in_tabs.set_active(st) st = app.config.get('show_chatstate_in_roster') self._ui.show_chatstate_in_roster.set_active(st) st = app.config.get('show_chatstate_in_banner') self._ui.show_chatstate_in_banner.set_active(st) ### Notifications tab ### ## Visual Notifications # Systray icon if app.config.get('trayicon') == 'never': self._ui.systray_combobox.set_active(0) elif app.config.get('trayicon') == 'on_event': self._ui.systray_combobox.set_active(1) else: # always self._ui.systray_combobox.set_active(2) # Notify on new event if app.config.get('autopopup'): self._ui.on_event_received_combobox.set_active(0) elif app.config.get('notify_on_new_message'): self._ui.on_event_received_combobox.set_active(1) else: # only show in roster self._ui.on_event_received_combobox.set_active(2) # Notify on online statuses st = app.config.get('notify_on_signin') self._ui.notify_on_signin_checkbutton.set_active(st) # Notify on offline statuses st = app.config.get('notify_on_signout') self._ui.notify_on_signout_checkbutton.set_active(st) # Auto popup when away st = app.config.get('autopopupaway') self._ui.auto_popup_away_checkbutton.set_active(st) # Auto popup when chat already open st = app.config.get('autopopup_chat_opened') self._ui.auto_popup_chat_opened_checkbutton.set_active(st) ## Sounds # Sounds if app.config.get('sounds_on'): self._ui.play_sounds_checkbutton.set_active(True) else: self._ui.manage_sounds_button.set_sensitive(False) # Allow sounds when dnd st = app.config.get('sounddnd') self._ui.sound_dnd_checkbutton.set_active(st) #### Status tab ### # Auto away st = app.config.get('autoaway') self._ui.auto_away_checkbutton.set_active(st) # Auto away time st = app.config.get('autoawaytime') self._ui.auto_away_time_spinbutton.set_value(st) self._ui.auto_away_time_spinbutton.set_sensitive( app.config.get('autoaway')) # Auto away message st = app.config.get('autoaway_message') self._ui.auto_away_message_entry.set_text(st) self._ui.auto_away_message_entry.set_sensitive( app.config.get('autoaway')) # Auto xa st = app.config.get('autoxa') self._ui.auto_xa_checkbutton.set_active(st) # Auto xa time st = app.config.get('autoxatime') self._ui.auto_xa_time_spinbutton.set_value(st) self._ui.auto_xa_time_spinbutton.set_sensitive( app.config.get('autoxa')) # Auto xa message st = app.config.get('autoxa_message') self._ui.auto_xa_message_entry.set_text(st) self._ui.auto_xa_message_entry.set_sensitive(app.config.get('autoxa')) if not idle.Monitor.is_available(): self._ui.autoaway_table.set_sensitive(False) # Restore last status st = self.get_per_account_option('restore_last_status') if st == 'mixed': self._ui.restore_last_status_checkbutton.set_inconsistent(True) else: self._ui.restore_last_status_checkbutton.set_active(st) # Ask for status when online/offline st = app.config.get('ask_online_status') self._ui.prompt_online_status_message_checkbutton.set_active(st) st = app.config.get('ask_offline_status') self._ui.prompt_offline_status_message_checkbutton.set_active(st) # Default status messages self.fill_default_msg_treeview() # Status messages renderer = Gtk.CellRendererText() renderer.connect('edited', self.on_msg_cell_edited) renderer.set_property('editable', True) col = Gtk.TreeViewColumn('name', renderer, text=0) self._ui.msg_treeview.append_column(col) self.fill_msg_treeview() buf = self._ui.msg_textview.get_buffer() buf.connect('end-user-action', self.on_msg_textview_changed) ### Style tab ### # Themes self.changed_id = self._ui.theme_combobox.connect( 'changed', self.on_theme_combobox_changed) self.update_theme_list() # Dark theme self._ui.dark_theme_combobox.set_active_id( str(app.config.get('dark_theme'))) # Emoticons emoticon_themes = helpers.get_available_emoticon_themes() for theme in emoticon_themes: self._ui.emoticons_combobox.append_text(theme) config_theme = app.config.get('emoticons_theme') if config_theme not in emoticon_themes: config_theme = 'font' self._ui.emoticons_combobox.set_id_column(0) self._ui.emoticons_combobox.set_active_id(config_theme) self._ui.ascii_emoticons.set_active(app.config.get('ascii_emoticons')) # Iconset model = Gtk.ListStore(str, str) renderer_image = Gtk.CellRendererPixbuf() renderer_text = Gtk.CellRendererText() renderer_text.set_property('xpad', 5) self._ui.iconset_combobox.pack_start(renderer_image, False) self._ui.iconset_combobox.pack_start(renderer_text, True) self._ui.iconset_combobox.add_attribute(renderer_text, 'text', 1) self._ui.iconset_combobox.add_attribute(renderer_image, 'icon_name', 0) self._ui.iconset_combobox.set_model(model) for index, iconset_name in enumerate(get_available_iconsets()): icon_name = get_icon_name('online', iconset=iconset_name) model.append([icon_name, iconset_name]) if app.config.get('iconset') == iconset_name: self._ui.iconset_combobox.set_active(index) # Use transports iconsets st = app.config.get('use_transports_iconsets') self._ui.transports_iconsets_checkbutton.set_active(st) ### Audio/Video tab ### def create_av_combobox(opt_name, device_dict, config_name=None, key=None): combobox = self._ui.get_object(opt_name + '_combobox') cell = Gtk.CellRendererText() cell.set_property('ellipsize', Pango.EllipsizeMode.END) cell.set_property('ellipsize-set', True) combobox.pack_start(cell, True) combobox.add_attribute(cell, 'text', 0) model = Gtk.ListStore(str, str) combobox.set_model(model) if config_name: config = app.config.get(config_name) else: config = app.config.get(opt_name + '_device') for index, (name, value) in enumerate( sorted(device_dict.items(), key=key)): model.append((name, value)) if config == value: combobox.set_active(index) if HAS_GST and app.is_installed('FARSTREAM'): create_av_combobox('audio_input', AudioInputManager().get_devices()) create_av_combobox('audio_output', AudioOutputManager().get_devices()) create_av_combobox('video_input', VideoInputManager().get_devices()) create_av_combobox('video_output', VideoOutputManager().get_devices()) create_av_combobox('video_framerate', {_('Default'): '', '15fps': '15/1', '10fps': '10/1', '5fps': '5/1', '2.5fps': '5/2'}, 'video_framerate', key=lambda x: -1 if \ not x[1] else float(x[0][:-3])) create_av_combobox('video_size', {_('Default'): '', '800x600': '800x600', '640x480': '640x480', '320x240': '320x240'}, 'video_size', key=lambda x: -1 if \ not x[1] else int(x[0][:3])) st = app.config.get('video_see_self') self._ui.video_see_self_checkbutton.set_active(st) else: for opt_name in ('audio_input', 'audio_output', 'video_input', 'video_output', 'video_framerate', 'video_size'): combobox = self._ui.get_object(opt_name + '_combobox') combobox.set_sensitive(False) # STUN st = app.config.get('use_stun_server') self._ui.stun_checkbutton.set_active(st) self._ui.stun_server_entry.set_text(app.config.get('stun_server')) if not st: self._ui.stun_server_entry.set_sensitive(False) ### Advanced tab ### ## Applications (open links with) if os.name == 'nt': self._ui.custom_apps_frame.set_no_show_all(True) self._ui.custom_apps_frame.hide() else: self._ui.custom_apps_frame.hide() self._ui.custom_apps_frame.set_no_show_all(True) if app.config.get('autodetect_browser_mailer'): self._ui.applications_combobox.set_active(0) else: self._ui.applications_combobox.set_active(1) self._ui.custom_apps_frame.show() self._ui.custom_browser_entry.set_text( app.config.get('custombrowser')) self._ui.custom_mail_client_entry.set_text( app.config.get('custommailapp')) self._ui.custom_file_manager_entry.set_text( app.config.get('custom_file_manager')) ## Miscellaneous # Proxy self.update_proxy_list() # Log status changes of contacts st = app.config.get('log_contact_status_changes') self._ui.log_show_changes_checkbutton.set_active(st) # Enable debug logging if sys.platform == 'win32': self._ui.enable_logging.set_active(app.get_win_debug_mode()) self._ui.enable_logging.show() self._ui.connect_signals(self) self.connect('key-press-event', self._on_key_press) self._ui.msg_treeview.get_model().connect( 'row-changed', self.on_msg_treemodel_row_changed) self._ui.msg_treeview.get_model().connect( 'row-deleted', self.on_msg_treemodel_row_deleted) self._ui.default_msg_treeview.get_model().connect( 'row-changed', self.on_default_msg_treemodel_row_changed) self.sounds_preferences = None self.theme_preferences = None self.show_all()
def _on_accept_button_clicked(self, _widget): model = self._ui.items_list_treeview.get_model() iter_ = model.get_iter_first() if self.action == 'add': count = 0 while iter_: if model[iter_][0]: count += 1 # It is selected message = _('%s suggested me to add you to my ' 'contact list.' % self.jid_from) # Keep same groups and same nickname groups = model[iter_][3].split(', ') if groups == ['']: groups = [] jid = model[iter_][1] if app.jid_is_transport(self.jid_from): con = app.connections[self.account] con.get_module('Presence').automatically_added.append( jid) app.interface.roster.req_sub(self, jid, message, self.account, groups=groups, nickname=model[iter_][2], auto_auth=True) iter_ = model.iter_next(iter_) InformationDialog( i18n.ngettext('Added %d contact', 'Added %d contacts', count, count, count)) elif self.action == 'modify': count = 0 while iter_: if model[iter_][0]: count += 1 # It is selected jid = model[iter_][1] # Keep same groups and same nickname groups = model[iter_][3].split(', ') if groups == ['']: groups = [] for contact in app.contacts.get_contact(self.account, jid): contact.name = model[iter_][2] con = app.connections[self.account] con.get_module('Roster').update_contact( jid, model[iter_][2], groups) con.get_module('Roster').draw_contact(jid, self.account) # Update opened chats ctrl = app.interface.msg_win_mgr.get_control( jid, self.account) if ctrl: ctrl.update_ui() win = app.interface.msg_win_mgr.get_window( jid, self.account) win.redraw_tab(ctrl) win.show_title() iter_ = model.iter_next(iter_) elif self.action == 'delete': count = 0 while iter_: if model[iter_][0]: count += 1 # It is selected jid = model[iter_][1] app.connections[self.account].get_module( 'Presence').unsubscribe(jid) app.interface.roster.remove_contact(jid, self.account) app.contacts.remove_jid(self.account, jid) iter_ = model.iter_next(iter_) InformationDialog( i18n.ngettext('Removed %d contact', 'Removed %d contacts', count, count, count)) self.destroy()
def __init__(self): Gtk.ApplicationWindow.__init__(self) self.set_application(app.app) self.set_position(Gtk.WindowPosition.CENTER) self.set_show_menubar(False) self.set_title(_('Preferences')) self._ui = get_builder('preferences_window.ui') self.add(self._ui.preferences_window) ### General tab ### ## Behavior of Windows and Tabs # Set default for single window type choices = c_config.opt_one_window_types type_ = app.config.get('one_message_window') if type_ in choices: self._ui.one_window_type_combobox.set_active(choices.index(type_)) else: self._ui.one_window_type_combobox.set_active(0) # Show roster on startup choices = c_config.opt_show_roster_on_startup type_ = app.config.get('show_roster_on_startup') if type_ in choices: self._ui.show_roster_on_startup.set_active(choices.index(type_)) else: self._ui.show_roster_on_startup.set_active(0) # Quit on roster x st = app.config.get('quit_on_roster_x_button') self._ui.quit_on_roster_x_checkbutton.set_active(st) # Tab placement st = app.config.get('tabs_position') if st == 'top': self._ui.tabs_placement.set_active(0) elif st == 'bottom': self._ui.tabs_placement.set_active(1) elif st == 'left': self._ui.tabs_placement.set_active(2) else: # right self._ui.tabs_placement.set_active(3) # Show avatar in tabs st = app.config.get('show_avatar_in_tabs') self._ui.show_avatar_in_tabs_checkbutton.set_active(st) ## Contact List Appearance # Display avatars in roster st = app.config.get('show_avatars_in_roster') self._ui.show_avatars_in_roster_checkbutton.set_active(st) # Display status msg under contact name in roster st = app.config.get('show_status_msgs_in_roster') self._ui.show_status_msgs_in_roster_checkbutton.set_active(st) # Display PEP in roster st1 = app.config.get('show_mood_in_roster') st2 = app.config.get('show_activity_in_roster') st3 = app.config.get('show_tunes_in_roster') st4 = app.config.get('show_location_in_roster') if st1 == st2 == st3 == st4: self._ui.show_pep_in_roster_checkbutton.set_active(st1) else: self._ui.show_pep_in_roster_checkbutton.set_inconsistent(True) # Sort contacts by show st = app.config.get('sort_by_show_in_roster') self._ui.sort_by_show_in_roster_checkbutton.set_active(st) st = app.config.get('sort_by_show_in_muc') self._ui.sort_by_show_in_muc_checkbutton.set_active(st) ### Chat tab ### ## General Settings # Enable auto copy st = app.config.get('auto_copy') self._ui.auto_copy.set_active(st) ## Chat Settings # Use speller if app.is_installed('GSPELL'): st = app.config.get('use_speller') self._ui.speller_checkbutton.set_active(st) else: self._ui.speller_checkbutton.set_sensitive(False) # XEP-0184 positive ack st = app.config.get('positive_184_ack') self._ui.positive_184_ack_checkbutton.set_active(st) # Ignore XHTML st = app.config.get('show_xhtml') self._ui.xhtml_checkbutton.set_active(st) # Print status messages in single chats st = app.config.get('print_status_in_chats') self._ui.print_status_in_chats_checkbutton.set_active(st) # Show subject on join st = app.config.get('show_subject_on_join') self._ui.subject_on_join_checkbutton.set_active(st) # Group chat settings threshold_model = self._ui.sync_threshold_combobox.get_model() days = app.config.get_options('threshold_options', return_type=int) for day in days: if day == 0: label = _('No threshold') else: label = ngettext('%i day', '%i days', day, day, day) threshold_model.append([str(day), label]) public_threshold = app.config.get('public_room_sync_threshold') self._ui.sync_threshold_combobox.set_id_column(0) self._ui.sync_threshold_combobox.set_active_id(str(public_threshold)) st = app.config.get('print_join_left_default') self._ui.join_leave_checkbutton.set_active(st) st = app.config.get('print_status_muc_default') self._ui.status_change_checkbutton.set_active(st) # Displayed chat state notifications st = app.config.get('show_chatstate_in_tabs') self._ui.show_chatstate_in_tabs.set_active(st) st = app.config.get('show_chatstate_in_roster') self._ui.show_chatstate_in_roster.set_active(st) st = app.config.get('show_chatstate_in_banner') self._ui.show_chatstate_in_banner.set_active(st) ### Notifications tab ### ## Visual Notifications # Systray icon if app.config.get('trayicon') == 'never': self._ui.systray_combobox.set_active(0) elif app.config.get('trayicon') == 'on_event': self._ui.systray_combobox.set_active(1) else: # always self._ui.systray_combobox.set_active(2) # Notify on new event if app.config.get('autopopup'): self._ui.on_event_received_combobox.set_active(0) elif app.config.get('notify_on_new_message'): self._ui.on_event_received_combobox.set_active(1) else: # only show in roster self._ui.on_event_received_combobox.set_active(2) # Notify on online statuses st = app.config.get('notify_on_signin') self._ui.notify_on_signin_checkbutton.set_active(st) # Notify on offline statuses st = app.config.get('notify_on_signout') self._ui.notify_on_signout_checkbutton.set_active(st) # Auto popup when away st = app.config.get('autopopupaway') self._ui.auto_popup_away_checkbutton.set_active(st) # Auto popup when chat already open st = app.config.get('autopopup_chat_opened') self._ui.auto_popup_chat_opened_checkbutton.set_active(st) ## Sounds # Sounds if app.config.get('sounds_on'): self._ui.play_sounds_checkbutton.set_active(True) else: self._ui.manage_sounds_button.set_sensitive(False) # Allow sounds when dnd st = app.config.get('sounddnd') self._ui.sound_dnd_checkbutton.set_active(st) #### Status tab ### # Auto away st = app.config.get('autoaway') self._ui.auto_away_checkbutton.set_active(st) # Auto away time st = app.config.get('autoawaytime') self._ui.auto_away_time_spinbutton.set_value(st) self._ui.auto_away_time_spinbutton.set_sensitive( app.config.get('autoaway')) # Auto away message st = app.config.get('autoaway_message') self._ui.auto_away_message_entry.set_text(st) self._ui.auto_away_message_entry.set_sensitive( app.config.get('autoaway')) # Auto xa st = app.config.get('autoxa') self._ui.auto_xa_checkbutton.set_active(st) # Auto xa time st = app.config.get('autoxatime') self._ui.auto_xa_time_spinbutton.set_value(st) self._ui.auto_xa_time_spinbutton.set_sensitive( app.config.get('autoxa')) # Auto xa message st = app.config.get('autoxa_message') self._ui.auto_xa_message_entry.set_text(st) self._ui.auto_xa_message_entry.set_sensitive(app.config.get('autoxa')) if not idle.Monitor.is_available(): self._ui.autoaway_table.set_sensitive(False) # Restore last status st = self.get_per_account_option('restore_last_status') if st == 'mixed': self._ui.restore_last_status_checkbutton.set_inconsistent(True) else: self._ui.restore_last_status_checkbutton.set_active(st) # Ask for status when online/offline st = app.config.get('ask_online_status') self._ui.prompt_online_status_message_checkbutton.set_active(st) st = app.config.get('ask_offline_status') self._ui.prompt_offline_status_message_checkbutton.set_active(st) # Default status messages self.fill_default_msg_treeview() # Status messages renderer = Gtk.CellRendererText() renderer.connect('edited', self.on_msg_cell_edited) renderer.set_property('editable', True) col = Gtk.TreeViewColumn('name', renderer, text=0) self._ui.msg_treeview.append_column(col) self.fill_msg_treeview() buf = self._ui.msg_textview.get_buffer() buf.connect('end-user-action', self.on_msg_textview_changed) ### Style tab ### # Themes self.changed_id = self._ui.theme_combobox.connect( 'changed', self.on_theme_combobox_changed) self.update_theme_list() # Dark theme self._ui.dark_theme_combobox.set_active_id( str(app.config.get('dark_theme'))) # Emoticons emoticon_themes = helpers.get_available_emoticon_themes() for theme in emoticon_themes: self._ui.emoticons_combobox.append_text(theme) config_theme = app.config.get('emoticons_theme') if config_theme not in emoticon_themes: config_theme = 'font' self._ui.emoticons_combobox.set_id_column(0) self._ui.emoticons_combobox.set_active_id(config_theme) self._ui.ascii_emoticons.set_active(app.config.get('ascii_emoticons')) # Iconset model = Gtk.ListStore(str, str) renderer_image = Gtk.CellRendererPixbuf() renderer_text = Gtk.CellRendererText() renderer_text.set_property('xpad', 5) self._ui.iconset_combobox.pack_start(renderer_image, False) self._ui.iconset_combobox.pack_start(renderer_text, True) self._ui.iconset_combobox.add_attribute(renderer_text, 'text', 1) self._ui.iconset_combobox.add_attribute(renderer_image, 'icon_name', 0) self._ui.iconset_combobox.set_model(model) for index, iconset_name in enumerate(get_available_iconsets()): icon_name = get_icon_name('online', iconset=iconset_name) model.append([icon_name, iconset_name]) if app.config.get('iconset') == iconset_name: self._ui.iconset_combobox.set_active(index) # Use transports iconsets st = app.config.get('use_transports_iconsets') self._ui.transports_iconsets_checkbutton.set_active(st) ### Audio/Video tab ### def create_av_combobox( opt_name, device_dict, config_name=None, # This key is there to give the first index to autovideosrc and co. key=lambda x: '' if x[1].startswith('auto') else x[0].lower()): combobox = self._ui.get_object(opt_name + '_combobox') cell = Gtk.CellRendererText() cell.set_property('ellipsize', Pango.EllipsizeMode.END) cell.set_property('ellipsize-set', True) combobox.pack_start(cell, True) combobox.add_attribute(cell, 'text', 0) model = Gtk.ListStore(str, str) combobox.set_model(model) if config_name: config = app.config.get(config_name) else: config = app.config.get(opt_name + '_device') for index, (name, value) in enumerate( sorted(device_dict.items(), key=key)): model.append((name, value)) if config == value: combobox.set_active(index) if HAS_GST and app.is_installed('FARSTREAM'): create_av_combobox('audio_input', AudioInputManager().get_devices()) create_av_combobox('audio_output', AudioOutputManager().get_devices()) create_av_combobox('video_input', VideoInputManager().get_devices()) create_av_combobox('video_framerate', { _('Default'): '', '15fps': '15/1', '10fps': '10/1', '5fps': '5/1', '2.5fps': '5/2' }, 'video_framerate', key=lambda x: -1 if not x[1] else float(x[0][:-3])) create_av_combobox('video_size', { _('Default'): '', '800x600': '800x600', '640x480': '640x480', '320x240': '320x240' }, 'video_size', key=lambda x: -1 if not x[1] else int(x[0][:3])) st = app.config.get('video_see_self') self._ui.video_see_self_checkbutton.set_active(st) def on_av_map(tab): label = self._ui.selected_video_output sink, widget, name = self.setup_video_output() if sink is None: log.error( 'Failed to obtain a working Gstreamer GTK+ sink, ' 'video support will be disabled') self._ui.video_input_combobox.set_sensitive(False) label.set_markup( _('<span color="red" font-weight="bold">' 'Unavailable</span>, video support will be disabled') ) return text = '' if name == 'gtkglsink': text = _('<span color="green" font-weight="bold">' 'OpenGL</span> accelerated') elif name == 'gtksink': text = _('<span color="yellow" font-weight="bold">' 'Unaccelerated</span>') label.set_markup(text) if self.av_pipeline is None: self.av_pipeline = Gst.Pipeline.new('preferences-pipeline') else: self.av_pipeline.set_state(Gst.State.NULL) self.av_pipeline.add(sink) self.av_sink = sink if self.av_widget is not None: tab.remove(self.av_widget) tab.add(widget) self.av_widget = widget src_name = app.config.get('video_input_device') try: self.av_src = Gst.parse_bin_from_description( src_name, True) except GLib.Error: log.error( 'Failed to parse "%s" as Gstreamer element,' ' falling back to autovideosrc', src_name) self.av_src = None if self.av_src is not None: self.av_pipeline.add(self.av_src) self.av_src.link(self.av_sink) self.av_pipeline.set_state(Gst.State.PLAYING) else: # Parsing the pipeline stored in video_input_device failed, # let’s try the default one. self.av_src = Gst.ElementFactory.make('autovideosrc', None) if self.av_src is None: log.error( 'Failed to obtain a working Gstreamer source,' ' video will be disabled.') self._ui.video_input_combobox.set_sensitive(False) return # Great, this succeeded, let’s store it back into the # config and use it. We’ve made autovideosrc the first # element in the combobox so we can pick index 0 without # worry. combobox = self._ui.video_input_combobox combobox.set_active(0) def on_av_unmap(tab): if self.av_pipeline is not None: self.av_pipeline.set_state(Gst.State.NULL) if self.av_src is not None: self.av_pipeline.remove(self.av_src) self.av_src = None if self.av_sink is not None: self.av_pipeline.remove(self.av_sink) self.av_sink = None if self.av_widget is not None: tab.remove(self.av_widget) self.av_widget = None self.av_pipeline = None self.av_pipeline = None self.av_src = None self.av_sink = None self.av_widget = None tab = self._ui.audio_video_tab tab.connect('map', on_av_map) tab.connect('unmap', on_av_unmap) else: for opt_name in ('audio_input', 'audio_output', 'video_input', 'video_framerate', 'video_size'): combobox = self._ui.get_object(opt_name + '_combobox') combobox.set_sensitive(False) # STUN st = app.config.get('use_stun_server') self._ui.stun_checkbutton.set_active(st) self._ui.stun_server_entry.set_text(app.config.get('stun_server')) if not st: self._ui.stun_server_entry.set_sensitive(False) ### Advanced tab ### ## Miscellaneous # Proxy self.update_proxy_list() # Log status changes of contacts st = app.config.get('log_contact_status_changes') self._ui.log_show_changes_checkbutton.set_active(st) self._ui.enable_logging.set_active(app.get_debug_mode()) self._ui.enable_logging.show() self._ui.connect_signals(self) self.connect('key-press-event', self._on_key_press) self._ui.msg_treeview.get_model().connect( 'row-changed', self.on_msg_treemodel_row_changed) self._ui.msg_treeview.get_model().connect( 'row-deleted', self.on_msg_treemodel_row_deleted) self._ui.default_msg_treeview.get_model().connect( 'row-changed', self.on_default_msg_treemodel_row_changed) self.sounds_preferences = None self.theme_preferences = None self.show_all()