Daniel Brötzmann pushed to branch mainwindow at gajim / gajim
Commits: ca496e71 by wurstsalat at 2021-03-04T20:46:36+01:00 Roster: Add actions
- - - - -
6 changed files:
- gajim/chat_control.py - gajim/gtk/account_page.py - gajim/gtk/chat_list.py - gajim/gtk/main.py - gajim/gtk/roster.py - gajim/gui_menu_builder.py
Changes:
===================================== gajim/chat_control.py ===================================== @@ -397,34 +397,10 @@ def _on_add_to_roster(self, _action, _param): AddNewContactWindow(self.account, self.contact.jid)
def _on_block_contact(self, _action, _param): - def _block_contact(report=None): - con = app.connections[self.account] - con.get_module('Blocking').block([self.contact.jid], report=report) - - self.parent_win.remove_tab(self, None, force=True) - if _('Not in contact list') in self.contact.get_shown_groups(): - app.interface.roster.remove_contact( - self.contact.jid, self.account, force=True, backend=True) - return - app.interface.roster.draw_contact(self.contact.jid, self.account) - - ConfirmationDialog( - _('Block Contact'), - _('Really block this contact?'), - _('You will appear offline for this contact and you will ' - 'not receive further messages.'), - [DialogButton.make('Cancel'), - DialogButton.make('OK', - text=_('_Report Spam'), - callback=_block_contact, - kwargs={'report': 'spam'}), - DialogButton.make('Remove', - text=_('_Block'), - callback=_block_contact)], - modal=False).show() + app.window.block_contact(self.account, self.contact.jid)
def _on_information(self, _action, _param): - app.interface.roster.on_info(None, self.contact, self.account) + app.window.contact_info(self.account, self.contact.jid)
def _on_invite_contacts(self, _action, _param): """
===================================== gajim/gtk/account_page.py ===================================== @@ -37,6 +37,9 @@ def __init__(self, account): self._roster = Roster(account) self._ui.roster_box.add(self._roster)
+ self._ui.paned.set_position(app.settings.get('chat_handle_position')) + self._ui.paned.connect('button-release-event', self._on_button_release) + self._ui.connect_signals(self) self.show_all()
@@ -46,6 +49,16 @@ def _on_account_settings(self, _button): window = open_window('AccountsWindow') window.select_account(self._account)
+ @staticmethod + def _on_button_release(paned, event): + if event.window != paned.get_handle_window(): + return + position = paned.get_position() + app.settings.set('chat_handle_position', position) + + def get_roster(self): + return self._roster + def update(self): account_label = app.settings.get_account_setting( self._account, 'account_label')
===================================== gajim/gtk/chat_list.py ===================================== @@ -418,7 +418,9 @@ def _on_state_flags_changed(self, _listboxrow, *args): self._ui.revealer.set_reveal_child(False)
def _on_close_button_clicked(self, _button): - app.window.remove_chat(self.workspace_id, self.account, self.jid) + app.window.activate_action( + 'remove-chat', + GLib.Variant('as', [self.account, self.jid]))
def set_timestamp(self, timestamp): self._timestamp = timestamp
===================================== gajim/gtk/main.py ===================================== @@ -7,20 +7,23 @@
from gajim.common import app from gajim.common import ged +from gajim.common.helpers import ask_for_status_message +from gajim.common.helpers import jid_is_blocked from gajim.common.i18n import _ -from gajim.gui.util import get_builder -from gajim.gui.util import load_icon +from gajim.common.nec import EventHelper + from gajim.gui.account_page import AccountPage +from gajim.gui.adhoc import AdHocCommand from gajim.gui.chat_list_stack import ChatListStack from gajim.gui.chat_stack import ChatStack from gajim.gui.account_side_bar import AccountSideBar from gajim.gui.workspace_side_bar import WorkspaceSideBar - -from gajim.common.helpers import ask_for_status_message from gajim.gui.dialogs import DialogButton from gajim.gui.dialogs import ConfirmationDialog +from gajim.gui.util import get_builder +from gajim.gui.util import load_icon
-from gajim.common.nec import EventHelper +from gajim.vcard import VcardWindow
from .util import open_window
@@ -425,11 +428,14 @@ def move_chat_to_workspace(self, new_workspace_id, account, jid): self._chat_list_stack.store_open_chats(new_workspace_id)
def _remove_chat(self, _action, param): - workspace_id, account, jid = param.unpack() - self.remove_chat(workspace_id, account, jid) + account, jid = param.unpack() + self.remove_chat(account, jid)
- def remove_chat(self, workspace_id, account, jid): - self._chat_list_stack.remove_chat(workspace_id, account, jid) + def remove_chat(self, account, jid): + for workspace_id in app.settings.get_workspaces(): + if self.chat_exists_for_workspace(workspace_id, account, jid): + self._chat_list_stack.remove_chat(workspace_id, account, jid) + return
def chat_exists(self, account, jid): return self._chat_list_stack.contains_chat(account, jid) @@ -447,14 +453,91 @@ def get_active_control(self): return None return self.get_control(chat.account, chat.jid)
+ def get_controls(self, account=None): + return self._chat_stack.get_controls(account) + def _add_accounts(self): for account in list(app.connections.keys()): account_page = AccountPage(account) self._account_pages[account] = account_page self._ui.main_stack.add_named(account_page, account)
- def get_controls(self, account=None): - return self._chat_stack.get_controls(account) + @staticmethod + def contact_info(account, jid): + client = app.get_client(account) + contact = client.get_module('Contacts').get_contact(jid) + + # TODO: VcardWindow does not work with new type Contacts + info = app.interface.instances[account]['infos'] + if contact.jid in info: + info[contact.jid].window.present() + else: + info[contact.jid] = VcardWindow(contact, account) + + @staticmethod + def execute_command(account, jid): + # TODO: Resource? + AdHocCommand(account, jid) + + def block_contact(self, account, jid): + client = app.get_client(account) + + if jid_is_blocked(account, jid): + client.get_module('Blocking').unblock([jid]) + roster = self._account_pages[account].get_roster() + roster.draw_contact(jid) + return + + # TODO: Keep "confirm_block" setting? + def _block_contact(report=None): + app.events.remove_events(account, jid) + + contact = client.get_module('Contacts').get_contact(jid) + client.get_module('Blocking').block([jid], report) + if not contact.is_in_roster: + self.remove_chat(account, jid) + return + + roster = self._account_pages[account].get_roster() + roster.draw_contact(jid) + # TODO: draw_contact draws too early (not blocked yet) + # TODO: Draw ChatList row differently? + + ConfirmationDialog( + _('Block Contact'), + _('Really block this contact?'), + _('You will appear offline for this contact and you ' + 'will not receive further messages.'), + [DialogButton.make('Cancel'), + DialogButton.make('OK', + text=_('_Report Spam'), + callback=_block_contact, + kwargs={'report': 'spam'}), + DialogButton.make('Remove', + text=_('_Block'), + callback=_block_contact)], + modal=False).show() + + def remove_contact(self, account, jid): + def _remove_contact(): + self.remove_chat(account, jid) + roster = self._account_pages[account].get_roster() + roster.remove_contact(jid) + + client = app.get_client(account) + contact = client.get_module('Contacts').get_contact(jid) + sec_text = _('You are about to remove %(name)s (%(jid)s) from ' + 'your contact list.\n') % { + 'name': contact.name, + 'jid': jid} + # TODO: ConfirmationCheckDialog for subscription decision? + ConfirmationDialog( + _('Remove Contact'), + _('Remove contact from contact list'), + sec_text, + [DialogButton.make('Cancel'), + DialogButton.make('Remove', + callback=_remove_contact)]).show()
def _load_chats(self): for workspace_id in app.settings.get_workspaces():
===================================== gajim/gtk/roster.py ===================================== @@ -4,6 +4,7 @@ from enum import IntEnum
from gi.repository import Gdk +from gi.repository import Gio from gi.repository import GLib from gi.repository import Gtk from gi.repository import GObject @@ -12,6 +13,7 @@ from gajim.common import ged from gajim.common.const import AvatarSize from gajim.common.const import StyleAttr +from gajim.common.helpers import jid_is_blocked from gajim.common.i18n import _
from gajim.gui_menu_builder import get_roster_menu @@ -73,11 +75,70 @@ def __init__(self, account): self._ui.connect_signals(self)
self.register_events([ + ('account-connected', ged.CORE, self._on_account_state), + ('account-disconnected', ged.CORE, self._on_account_state), ('theme-update', ged.GUI2, self._on_theme_update), ])
+ self._add_actions() self._initial_draw()
+ def _add_actions(self): + actions = [ + ('contact-info', self._contact_info), + ('execute-command', self._execute_command), + ('block-contact', self._block_contact), + ('remove-contact', self._remove_contact), + ] + for action in actions: + action_name, func = action + act = Gio.SimpleAction.new( + f'{action_name}-{self._account}', GLib.VariantType.new('s')) + act.connect('activate', func) + app.window.add_action(act) + + def update_actions(self): + online = app.account_is_connected(self._account) + blocking_support = self._client.get_module('Blocking').supported + + app.window.lookup_action( + f'contact-info-{self._account}').set_enabled(online) + app.window.lookup_action( + f'execute-command-{self._account}').set_enabled(online) + app.window.lookup_action( + f'block-contact-{self._account}').set_enabled( + online and blocking_support) + app.window.lookup_action( + f'remove-contact-{self._account}').set_enabled(online) + + def _remove_actions(self): + actions = [ + 'contact-info', + 'execute-command', + 'block-contact', + 'remove-contact', + ] + for action in actions: + app.window.remove_action(f'{action}-{self._account}') + + def _on_account_state(self, _event): + self.update_actions() + + def _on_theme_update(self, _event): + self.redraw() + + def _contact_info(self, _action, param): + app.window.contact_info(self._account, param.get_string()) + + def _execute_command(self, _action, param): + app.window.execute_command(self._account, param.get_string()) + + def _block_contact(self, _action, param): + app.window.block_contact(self._account, param.get_string()) + + def _remove_contact(self, _action, param): + app.window.remove_contact(self._account, param.get_string()) + def _on_roster_row_activated(self, _treeview, path, _column): iter_ = self._store.get_iter(path) if self._store.iter_parent(iter_) is None: @@ -113,9 +174,6 @@ def _on_roster_button_press_event(self, treeview, event): def _on_focus_out(treeview, _param): treeview.get_selection().unselect_all()
- def _on_theme_update(self, _event): - self.redraw() - def _show_contact_menu(self, jid, treeview, event): menu = get_roster_menu(self._account, jid)
@@ -131,6 +189,7 @@ def _show_contact_menu(self, jid, treeview, event): popover.popup()
def _on_destroy(self, _roster): + self._remove_actions() self._contact_refs = {} self._group_refs = {} self._roster.set_model(None) @@ -163,8 +222,7 @@ def invalidate_sort(self): self.enable_sort(True)
def _initial_draw(self): - client = app.get_client(self._account) - for contact in client.get_module('Roster').iter_contacts(): + for contact in self._client.get_module('Roster').iter_contacts(): contact.connect('presence-update', self._on_presence_update) contact.connect('avatar-update', self._on_avatar_update) self._add_contact(contact) @@ -217,6 +275,27 @@ def _add_contact(self, contact): self._roster.get_model() is not None): self._roster.expand_row(group_path, False)
+ def remove_contact(self, jid): + # TODO: How to delete a roster item? + #self._client.get_module('Roster').delete_item(jid) + + iter_ = self._get_contact_iter(jid) + if not iter_: + return + + group_iter = self._store.iter_parent(iter_) + if group_iter is None: + raise ValueError('Trying to remove non-chil') + + self._store.remove(iter_) + del self._contact_refs[jid] + if not self._store.iter_has_child(group_iter): + group = self._store[group_iter][Column.JID_OR_GROUP] + del self._group_refs[group] + self._store.remove(group_iter) + + self.redraw() + def draw_groups(self): for group in self._group_refs: self.draw_group(group) @@ -242,9 +321,12 @@ def draw_contact(self, jid): return
contact = self._client.get_module('Contacts').get_contact(jid) + name = GLib.markup_escape_text(contact.name) + if jid_is_blocked(self._account, jid): + name = f'<span strikethrough="true">{name}</span>'
self.draw_avatar(contact) - self._store[iter_][Column.TEXT] = GLib.markup_escape_text(contact.name) + self._store[iter_][Column.TEXT] = name
def draw_avatar(self, contact): iter_ = self._get_contact_iter(str(contact.jid))
===================================== gajim/gui_menu_builder.py ===================================== @@ -797,17 +797,24 @@ def get_conv_context_menu(account, uri):
def get_roster_menu(account, jid): + if helpers.jid_is_blocked(account, jid): + block_label = _('Unblock') + else: + block_label = _('Block…') menu_items = [ - ('show-contact-info', _('Contact Info')), + ('contact-info', _('Information')), + ('execute-command', _('Execute Command…')), + ('block-contact', block_label), + ('remove-contact', _('Remove…')), ] + menu = Gio.Menu() for item in menu_items: action, label = item - action = f'win.{action}' + action = f'win.{action}-{account}' menuitem = Gio.MenuItem.new(label, action) - variant_list = GLib.Variant( - 'as', [account, str(jid)]) - menuitem.set_action_and_target_value(action, variant_list) + variant = GLib.Variant('s', str(jid)) + menuitem.set_action_and_target_value(action, variant) menu.append_item(menuitem)
return menu
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/ca496e710d1539bc4eca26b9b2dcab28d...