new context menu generation - builder, generators
This commit is contained in:
parent
7898363dcb
commit
c6192de9dd
7 changed files with 178 additions and 78 deletions
|
@ -2,6 +2,7 @@ from history.database import *
|
||||||
from contacts import basecontact, common
|
from contacts import basecontact, common
|
||||||
import utils.util as util
|
import utils.util as util
|
||||||
from messenger.messages import *
|
from messenger.messages import *
|
||||||
|
from contacts.contact_menu import *
|
||||||
from file_transfers import file_transfers as ft
|
from file_transfers import file_transfers as ft
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ class Contact(basecontact.BaseContact):
|
||||||
self._unsaved_messages += 1
|
self._unsaved_messages += 1
|
||||||
|
|
||||||
def get_last_message_text(self):
|
def get_last_message_text(self):
|
||||||
messages = list(filter(lambda x: x.get_type() <= 1 and x.get_owner() != MESSAGE_OWNER['FRIEND'], self._corr))
|
messages = list(filter(lambda x: x.get_type() <= 1 and x.get_owner() != MESSAGE_AUTHOR['FRIEND'], self._corr))
|
||||||
if messages:
|
if messages:
|
||||||
return messages[-1].get_data()[0]
|
return messages[-1].get_data()[0]
|
||||||
else:
|
else:
|
||||||
|
@ -103,19 +104,19 @@ class Contact(basecontact.BaseContact):
|
||||||
"""
|
"""
|
||||||
:return list of unsent messages
|
:return list of unsent messages
|
||||||
"""
|
"""
|
||||||
messages = filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr)
|
messages = filter(lambda x: x.get_owner() == MESSAGE_AUTHOR['NOT_SENT'], self._corr)
|
||||||
return list(messages)
|
return list(messages)
|
||||||
|
|
||||||
def get_unsent_messages_for_saving(self):
|
def get_unsent_messages_for_saving(self):
|
||||||
"""
|
"""
|
||||||
:return list of unsent messages for saving
|
:return list of unsent messages for saving
|
||||||
"""
|
"""
|
||||||
messages = filter(lambda x: x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr)
|
messages = filter(lambda x: x.get_type() <= 1 and x.get_owner() == MESSAGE_AUTHOR['NOT_SENT'], self._corr)
|
||||||
return list(map(lambda x: x.get_data(), messages))
|
return list(map(lambda x: x.get_data(), messages))
|
||||||
|
|
||||||
def mark_as_sent(self):
|
def mark_as_sent(self):
|
||||||
try:
|
try:
|
||||||
message = list(filter(lambda x: x.get_owner() == MESSAGE_OWNER['NOT_SENT'], self._corr))[0]
|
message = list(filter(lambda x: x.get_owner() == MESSAGE_AUTHOR['NOT_SENT'], self._corr))[0]
|
||||||
message.mark_as_sent()
|
message.mark_as_sent()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
util.log('Mark as sent ex: ' + str(ex))
|
util.log('Mark as sent ex: ' + str(ex))
|
||||||
|
@ -140,7 +141,7 @@ class Contact(basecontact.BaseContact):
|
||||||
def save_message(x):
|
def save_message(x):
|
||||||
if x.get_type() == 2 and (x.get_status() >= 2 or x.get_status() is None):
|
if x.get_type() == 2 and (x.get_status() >= 2 or x.get_status() is None):
|
||||||
return True
|
return True
|
||||||
return x.get_owner() == MESSAGE_OWNER['NOT_SENT']
|
return x.get_owner() == MESSAGE_AUTHOR['NOT_SENT']
|
||||||
|
|
||||||
old = filter(save_message, self._corr[:-SAVE_MESSAGES])
|
old = filter(save_message, self._corr[:-SAVE_MESSAGES])
|
||||||
self._corr = list(old) + self._corr[-SAVE_MESSAGES:]
|
self._corr = list(old) + self._corr[-SAVE_MESSAGES:]
|
||||||
|
@ -162,7 +163,7 @@ class Contact(basecontact.BaseContact):
|
||||||
self._unsaved_messages = 0
|
self._unsaved_messages = 0
|
||||||
else:
|
else:
|
||||||
self._corr = list(filter(lambda x: (x.get_type() == 2 and x.get_status() in ft.ACTIVE_FILE_TRANSFERS)
|
self._corr = list(filter(lambda x: (x.get_type() == 2 and x.get_status() in ft.ACTIVE_FILE_TRANSFERS)
|
||||||
or (x.get_type() <= 1 and x.get_owner() == MESSAGE_OWNER['NOT_SENT']),
|
or (x.get_type() <= 1 and x.get_owner() == MESSAGE_AUTHOR['NOT_SENT']),
|
||||||
self._corr))
|
self._corr))
|
||||||
self._unsaved_messages = len(self.get_unsent_messages())
|
self._unsaved_messages = len(self.get_unsent_messages())
|
||||||
|
|
||||||
|
@ -294,3 +295,10 @@ class Contact(basecontact.BaseContact):
|
||||||
return common.BaseTypingNotificationHandler.DEFAULT_HANDLER
|
return common.BaseTypingNotificationHandler.DEFAULT_HANDLER
|
||||||
|
|
||||||
typing_notification_handler = property(get_typing_notification_handler)
|
typing_notification_handler = property(get_typing_notification_handler)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
# Context menu support
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def get_context_menu_generator(self):
|
||||||
|
return BaseContactMenuGenerator(self)
|
||||||
|
|
144
toxygen/contacts/contact_menu.py
Normal file
144
toxygen/contacts/contact_menu.py
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
import utils.ui as util_ui
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
# Builder
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _create_menu(menu_name):
|
||||||
|
return QtWidgets.QMenu(menu_name or '')
|
||||||
|
|
||||||
|
|
||||||
|
class ContactMenuBuilder:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._actions = []
|
||||||
|
self._submenus = []
|
||||||
|
self._name = None
|
||||||
|
|
||||||
|
def with_name(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def with_action(self, text, handler):
|
||||||
|
self._actions.append((text, handler))
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def with_actions(self, actions):
|
||||||
|
self._actions.extend(actions)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def with_submenu(self, submenu):
|
||||||
|
self._add_submenu(submenu)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def with_optional_submenu(self, submenu):
|
||||||
|
if submenu is not None:
|
||||||
|
self._add_submenu(submenu)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def build(self): # TODO: actions order
|
||||||
|
menu = _create_menu(self._name)
|
||||||
|
|
||||||
|
for text, handler in self._actions:
|
||||||
|
action = menu.addAction(text)
|
||||||
|
action.triggered.connect(handler)
|
||||||
|
|
||||||
|
for submenu in self._submenus:
|
||||||
|
menu.addMenu(submenu)
|
||||||
|
|
||||||
|
return menu
|
||||||
|
|
||||||
|
def _add_submenu(self, submenu):
|
||||||
|
self._submenus.append(submenu)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
# Generators
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class BaseContactMenuGenerator:
|
||||||
|
|
||||||
|
def __init__(self, contact):
|
||||||
|
self._contact = contact
|
||||||
|
|
||||||
|
def generate(self, plugin_loader, contacts_manager, main_screen, settings, number):
|
||||||
|
return ContactMenuBuilder().build()
|
||||||
|
|
||||||
|
|
||||||
|
class FriendMenuGenerator(BaseContactMenuGenerator):
|
||||||
|
|
||||||
|
def generate(self, plugin_loader, contacts_manager, main_screen, settings, number):
|
||||||
|
history_menu = self._generate_history_menu(main_screen, number)
|
||||||
|
copy_menu = self._generate_copy_menu(main_screen)
|
||||||
|
plugins_menu = self._generate_plugins_menu(plugin_loader, number)
|
||||||
|
|
||||||
|
allowed = self._contact.tox_id in settings['auto_accept_from_friends']
|
||||||
|
auto = util_ui.tr('Disallow auto accept') if allowed else util_ui.tr('Allow auto accept')
|
||||||
|
|
||||||
|
builder = ContactMenuBuilder()
|
||||||
|
menu = (builder
|
||||||
|
.with_action(util_ui.tr('Set alias'), lambda: main_screen.set_alias(number))
|
||||||
|
.with_action(util_ui.tr('Chat history'), lambda: main_screen.clear_history(number))
|
||||||
|
.with_submenu(history_menu)
|
||||||
|
.with_submenu(copy_menu)
|
||||||
|
.with_action(auto, lambda: main_screen.auto_accept(number, not allowed))
|
||||||
|
.with_action(util_ui.tr('Remove friend'), lambda: main_screen.remove_friend(number))
|
||||||
|
.with_action(util_ui.tr('Block friend'), lambda: main_screen.block_friend(number))
|
||||||
|
.with_action(util_ui.tr('Notes'), lambda: main_screen.show_note(self._contact))
|
||||||
|
.with_optional_submenu(plugins_menu)
|
||||||
|
).build()
|
||||||
|
|
||||||
|
return menu
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
# Private methods
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _generate_history_menu(main_screen, number):
|
||||||
|
history_menu_builder = ContactMenuBuilder()
|
||||||
|
history_menu = (history_menu_builder
|
||||||
|
.with_name(util_ui.tr('Chat history'))
|
||||||
|
.with_action(util_ui.tr('Clear history'), lambda: main_screen.clear_history(number))
|
||||||
|
.with_action(util_ui.tr('Export as text'), lambda: main_screen.export_history(number))
|
||||||
|
.with_action(util_ui.tr('Export as HTML'), lambda: main_screen.export_history(number, False))
|
||||||
|
).build()
|
||||||
|
return history_menu
|
||||||
|
|
||||||
|
def _generate_copy_menu(self, main_screen):
|
||||||
|
copy_menu_builder = ContactMenuBuilder()
|
||||||
|
copy_menu = (copy_menu_builder
|
||||||
|
.with_name(util_ui.tr('Copy'))
|
||||||
|
.with_action(util_ui.tr('Name'), lambda: main_screen.copy_text(self._contact.name))
|
||||||
|
.with_action(util_ui.tr('Status message'), lambda: main_screen.copy_text(self._contact.name))
|
||||||
|
.with_action(util_ui.tr('Public key'), lambda: main_screen.copy_text(self._contact.tox_id))
|
||||||
|
).build()
|
||||||
|
|
||||||
|
return copy_menu
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _generate_plugins_menu(plugin_loader, number):
|
||||||
|
if plugin_loader is None:
|
||||||
|
return None
|
||||||
|
plugins_actions = plugin_loader.get_menu(number)
|
||||||
|
if not len(plugins_actions):
|
||||||
|
return None
|
||||||
|
plugins_menu_builder = ContactMenuBuilder()
|
||||||
|
plugins_menu = (plugins_menu_builder
|
||||||
|
.with_name(util_ui.tr('Plugins'))
|
||||||
|
.with_actions(plugins_actions)
|
||||||
|
)
|
||||||
|
|
||||||
|
return plugins_menu
|
||||||
|
|
||||||
|
def _generate_groups_menu(self, contacts_manager):
|
||||||
|
chats = contacts_manager.get_group_chats()
|
||||||
|
if not len(chats) or self._contact.status is None:
|
||||||
|
return None
|
|
@ -1,4 +1,3 @@
|
||||||
import utils.util as util
|
|
||||||
import common.tox_save as tox_save
|
import common.tox_save as tox_save
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from contacts import contact, common
|
from contacts import contact, common
|
||||||
from messenger.messages import *
|
from messenger.messages import *
|
||||||
import os
|
import os
|
||||||
|
from contacts.contact_menu import *
|
||||||
|
|
||||||
|
|
||||||
class Friend(contact.Contact):
|
class Friend(contact.Contact):
|
||||||
|
@ -46,6 +47,7 @@ class Friend(contact.Contact):
|
||||||
if message.get_data()[1] is not None:
|
if message.get_data()[1] is not None:
|
||||||
return True
|
return True
|
||||||
return os.path.exists(message.get_data()[0])
|
return os.path.exists(message.get_data()[0])
|
||||||
|
|
||||||
self._corr = list(filter(is_valid, self._corr))
|
self._corr = list(filter(is_valid, self._corr))
|
||||||
|
|
||||||
def delete_one_unsent_file(self, time):
|
def delete_one_unsent_file(self, time):
|
||||||
|
@ -81,3 +83,10 @@ class Friend(contact.Contact):
|
||||||
|
|
||||||
def get_typing_notification_handler(self):
|
def get_typing_notification_handler(self):
|
||||||
return self._typing_notification_handler
|
return self._typing_notification_handler
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
# Context menu support
|
||||||
|
# -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def get_context_menu_generator(self):
|
||||||
|
return FriendMenuGenerator(self)
|
||||||
|
|
|
@ -138,7 +138,7 @@ class PluginLoader():
|
||||||
if name in self._plugins and self._plugins[name][1]:
|
if name in self._plugins and self._plugins[name][1]:
|
||||||
self._plugins[name][0].command(text[len(name) + 1:])
|
self._plugins[name][0].command(text[len(name) + 1:])
|
||||||
|
|
||||||
def get_menu(self, menu, num):
|
def get_menu(self, num):
|
||||||
"""
|
"""
|
||||||
Return list of items for menu
|
Return list of items for menu
|
||||||
"""
|
"""
|
||||||
|
@ -146,7 +146,7 @@ class PluginLoader():
|
||||||
for elem in self._plugins.values():
|
for elem in self._plugins.values():
|
||||||
if elem[1]:
|
if elem[1]:
|
||||||
try:
|
try:
|
||||||
result.extend(elem[0].get_menu(menu, num))
|
result.extend(elem[0].get_menu(num))
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -76,12 +76,11 @@ class PluginSuperClass:
|
||||||
"""
|
"""
|
||||||
return self.__doc__
|
return self.__doc__
|
||||||
|
|
||||||
def get_menu(self, menu, row_number):
|
def get_menu(self, row_number):
|
||||||
"""
|
"""
|
||||||
This method creates items for menu which called on right click in list of friends
|
This method creates items for menu which called on right click in list of friends
|
||||||
:param menu: menu instance
|
|
||||||
:param row_number: number of selected row in list of contacts
|
:param row_number: number of selected row in list of contacts
|
||||||
:return list of QAction's
|
:return list of tuples (text, handler)
|
||||||
"""
|
"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
|
@ -576,63 +576,14 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
def friend_right_click(self, pos):
|
def friend_right_click(self, pos):
|
||||||
# TODO: move to contact?
|
# TODO: move to contact?
|
||||||
item = self.friends_list.itemAt(pos)
|
item = self.friends_list.itemAt(pos)
|
||||||
num = self.friends_list.indexFromItem(item).row()
|
number = self.friends_list.indexFromItem(item).row()
|
||||||
contact = self._contacts_manager.get_contact(num)
|
contact = self._contacts_manager.get_contact(number)
|
||||||
if contact is None:
|
if contact is None:
|
||||||
return
|
return
|
||||||
allowed = contact.tox_id in self._settings['auto_accept_from_friends']
|
|
||||||
auto = util_ui.tr('Disallow auto accept') if allowed else util_ui.tr('Allow auto accept')
|
|
||||||
if item is not None:
|
if item is not None:
|
||||||
self.listMenu = QtWidgets.QMenu()
|
generator = contact.get_context_menu_generator()
|
||||||
is_friend = type(contact) is Friend
|
self.listMenu = generator.generate(self._plugins_loader, self._contacts_manager, self,
|
||||||
if is_friend:
|
self._settings, number)
|
||||||
set_alias_item = self.listMenu.addAction(util_ui.tr('Set alias'))
|
|
||||||
set_alias_item.triggered.connect(lambda: self.set_alias(num))
|
|
||||||
|
|
||||||
history_menu = self.listMenu.addMenu(util_ui.tr('Chat history'))
|
|
||||||
clear_history_item = history_menu.addAction(util_ui.tr('Clear history'))
|
|
||||||
export_to_text_item = history_menu.addAction(util_ui.tr('Export as text'))
|
|
||||||
export_to_html_item = history_menu.addAction(util_ui.tr('Export as HTML'))
|
|
||||||
|
|
||||||
copy_menu = self.listMenu.addMenu(util_ui.tr('Copy'))
|
|
||||||
copy_name_item = copy_menu.addAction(util_ui.tr('Name'))
|
|
||||||
copy_status_item = copy_menu.addAction(util_ui.tr('Status message'))
|
|
||||||
if is_friend:
|
|
||||||
copy_key_item = copy_menu.addAction(util_ui.tr('Public key'))
|
|
||||||
|
|
||||||
auto_accept_item = self.listMenu.addAction(auto)
|
|
||||||
remove_item = self.listMenu.addAction(util_ui.tr('Remove friend'))
|
|
||||||
block_item = self.listMenu.addAction(util_ui.tr('Block friend'))
|
|
||||||
notes_item = self.listMenu.addAction(util_ui.tr('Notes'))
|
|
||||||
|
|
||||||
chats = self._contacts_manager.get_group_chats()
|
|
||||||
if len(chats) and contact.status is not None:
|
|
||||||
invite_menu = self.listMenu.addMenu(util_ui.tr('Invite to group chat'))
|
|
||||||
for i in range(len(chats)):
|
|
||||||
name, number = chats[i]
|
|
||||||
item = invite_menu.addAction(name)
|
|
||||||
item.triggered.connect(lambda: self.invite_friend_to_gc(num, number))
|
|
||||||
|
|
||||||
if self._plugins_loader is not None:
|
|
||||||
submenu = self._plugins_loader.get_menu(self.listMenu, num)
|
|
||||||
if len(submenu):
|
|
||||||
plug = self.listMenu.addMenu(util_ui.tr('Plugins'))
|
|
||||||
plug.addActions(submenu)
|
|
||||||
copy_key_item.triggered.connect(lambda: self.copy_friend_key(num))
|
|
||||||
remove_item.triggered.connect(lambda: self.remove_friend(num))
|
|
||||||
block_item.triggered.connect(lambda: self.block_friend(num))
|
|
||||||
auto_accept_item.triggered.connect(lambda: self.auto_accept(num, not allowed))
|
|
||||||
notes_item.triggered.connect(lambda: self.show_note(contact))
|
|
||||||
else:
|
|
||||||
leave_item = self.listMenu.addAction(util_ui.tr('Leave chat'))
|
|
||||||
set_title_item = self.listMenu.addAction(util_ui.tr('Set title'))
|
|
||||||
leave_item.triggered.connect(lambda: self.leave_gc(num))
|
|
||||||
set_title_item.triggered.connect(lambda: self.set_title(num))
|
|
||||||
clear_history_item.triggered.connect(lambda: self.clear_history(num))
|
|
||||||
copy_name_item.triggered.connect(lambda: self.copy_name(contact))
|
|
||||||
copy_status_item.triggered.connect(lambda: self.copy_status(contact))
|
|
||||||
export_to_text_item.triggered.connect(lambda: self.export_history(num))
|
|
||||||
export_to_html_item.triggered.connect(lambda: self.export_history(num, False))
|
|
||||||
parent_position = self.friends_list.mapToGlobal(QtCore.QPoint(0, 0))
|
parent_position = self.friends_list.mapToGlobal(QtCore.QPoint(0, 0))
|
||||||
self.listMenu.move(parent_position + pos)
|
self.listMenu.move(parent_position + pos)
|
||||||
self.listMenu.show()
|
self.listMenu.show()
|
||||||
|
@ -672,20 +623,10 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
friend = self.profile.get_contact(num)
|
friend = self.profile.get_contact(num)
|
||||||
self._contacts_manager.block_user(friend.tox_id)
|
self._contacts_manager.block_user(friend.tox_id)
|
||||||
|
|
||||||
def copy_friend_key(self, num):
|
|
||||||
tox_id = self._contacts_manager.friend_public_key(num)
|
|
||||||
clipboard = QtWidgets.QApplication.clipboard()
|
|
||||||
clipboard.setText(tox_id)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def copy_name(friend):
|
def copy_text(text):
|
||||||
clipboard = QtWidgets.QApplication.clipboard()
|
clipboard = QtWidgets.QApplication.clipboard()
|
||||||
clipboard.setText(friend.name)
|
clipboard.setText(text)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def copy_status(friend):
|
|
||||||
clipboard = QtWidgets.QApplication.clipboard()
|
|
||||||
clipboard.setText(friend.status_message)
|
|
||||||
|
|
||||||
def clear_history(self, num):
|
def clear_history(self, num):
|
||||||
self._contacts_manager.clear_history(num)
|
self._contacts_manager.clear_history(num)
|
||||||
|
|
Loading…
Reference in a new issue