history fixes - db cleanup

This commit is contained in:
ingvar1995 2018-05-15 22:51:42 +03:00
parent f1c63bb4e8
commit eef02a1173
11 changed files with 418 additions and 486 deletions

View file

@ -302,9 +302,10 @@ class App:
friend_items_factory = FriendItemsFactory(self._settings, self._ms) friend_items_factory = FriendItemsFactory(self._settings, self._ms)
self._friend_factory = FriendFactory(self._profile_manager, self._settings, self._tox, db, friend_items_factory) self._friend_factory = FriendFactory(self._profile_manager, self._settings, self._tox, db, friend_items_factory)
self._contacts_provider = ContactProvider(self._tox, self._friend_factory) self._contacts_provider = ContactProvider(self._tox, self._friend_factory)
history = History(self._contacts_provider, db, self._settings) history = None
messages_items_factory = MessagesItemsFactory(self._settings, self._plugin_loader, self._smiley_loader, messages_items_factory = MessagesItemsFactory(self._settings, self._plugin_loader, self._smiley_loader,
self._ms, history) self._ms, lambda m: history.delete_message(m))
history = History(self._contacts_provider, db, self._settings, self._ms, messages_items_factory)
self._contacts_manager = ContactsManager(self._tox, self._settings, self._ms, self._profile_manager, self._contacts_manager = ContactsManager(self._tox, self._settings, self._ms, self._profile_manager,
self._contacts_provider, history, self._tox_dns, self._contacts_provider, history, self._tox_dns,
messages_items_factory) messages_items_factory)

View file

@ -296,6 +296,7 @@ class ContactsManager:
Adds friend to list Adds friend to list
""" """
self._tox.friend_add_norequest(tox_id) self._tox.friend_add_norequest(tox_id)
self._history.add_friend_to_db(tox_id)
friend = self._contact_provider.get_friend_by_public_key(tox_id) friend = self._contact_provider.get_friend_by_public_key(tox_id)
self._contacts.append(friend) self._contacts.append(friend)

View file

@ -1,11 +1,10 @@
from contacts.friend import * from contacts.friend import *
from user_data.settings import *
from history.database import *
from file_transfers.file_transfers import * from file_transfers.file_transfers import *
import time import time
from contacts import basecontact from contacts import basecontact
from contacts.group_chat import * from contacts.group_chat import *
import utils.ui as util_ui import utils.ui as util_ui
import random
class Profile(basecontact.BaseContact): class Profile(basecontact.BaseContact):
@ -70,7 +69,6 @@ class Profile(basecontact.BaseContact):
def new_nospam(self): def new_nospam(self):
"""Sets new nospam part of tox id""" """Sets new nospam part of tox id"""
import random
self._tox.self_set_nospam(random.randint(0, 4294967295)) # no spam - uint32 self._tox.self_set_nospam(random.randint(0, 4294967295)) # no spam - uint32
self._tox_id = self._tox.self_get_address() self._tox_id = self._tox.self_get_address()
@ -106,58 +104,6 @@ class Profile(basecontact.BaseContact):
while i < self._messages.count() and not self._messages.itemWidget(self._messages.item(i)).mark_as_sent(): while i < self._messages.count() and not self._messages.itemWidget(self._messages.item(i)).mark_as_sent():
i += 1 i += 1
def delete_message(self, message_id):
friend = self.get_curr_friend()
friend.delete_message(time)
self._history.delete_message(friend.tox_id, message_id)
self.update()
# -----------------------------------------------------------------------------------------------------------------
# Friend, message and file transfer items creation
# -----------------------------------------------------------------------------------------------------------------
def create_message_item(self, text, time, owner, message_type, append=True):
if message_type == MESSAGE_TYPE['INFO_MESSAGE']:
name = ''
elif owner == MESSAGE_OWNER['FRIEND']:
name = self.get_active_name()
else:
name = self._name
pixmap = None
if self._show_avatars:
if owner == MESSAGE_OWNER['FRIEND']:
pixmap = self.get_curr_friend().get_pixmap()
else:
pixmap = self.get_pixmap()
return self._factory.create_message_item(text, time, name, owner != MESSAGE_OWNER['NOT_SENT'],
message_type, append, pixmap)
def create_gc_message_item(self, text, time, owner, name, message_type, append=True):
pixmap = None
if self._show_avatars:
if owner == MESSAGE_OWNER['FRIEND']:
pixmap = self.get_curr_friend().get_pixmap()
else:
pixmap = self.get_pixmap()
return self._factory.create_message_item(text, time, name, True,
message_type - 5, append, pixmap)
def create_file_transfer_item(self, tm, append=True):
data = list(tm.get_data())
data[3] = self.get_friend_by_number(data[4]).name if data[3] else self._name
return self._factory.create_file_transfer_item(data, append)
def create_unsent_file_item(self, message, append=True):
data = message.get_data()
return self._factory.create_unsent_file_item(os.path.basename(data[0]),
os.path.getsize(data[0]) if data[1] is None else len(data[1]),
self.name,
data[2],
append)
def create_inline_item(self, data, append=True):
return self._factory.create_inline_item(data, append)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Reset # Reset
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------

View file

@ -1,7 +1,7 @@
from file_transfers.file_transfers import * from file_transfers.file_transfers import *
from messenger.messages import * from messenger.messages import *
from history.database import MESSAGE_AUTHOR from history.database import MESSAGE_AUTHOR
from ui.list_items import * from ui.contact_items import *
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
import utils.util as util import utils.util as util

View file

@ -37,16 +37,6 @@ class Database:
except Exception as ex: except Exception as ex:
util.log('Db reading error: ' + str(ex)) util.log('Db reading error: ' + str(ex))
os.remove(path) os.remove(path)
db = self._connect()
cursor = db.cursor()
cursor.execute('CREATE TABLE IF NOT EXISTS contacts ('
' tox_id TEXT PRIMARY KEY,'
' contact_type INTEGER'
')')
db.close()
def _connect(self):
return connect(self._path, timeout=TIMEOUT)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Public methods # Public methods
@ -73,10 +63,8 @@ class Database:
db = self._connect() db = self._connect()
try: try:
cursor = db.cursor() cursor = db.cursor()
# cursor.execute('INSERT INTO contacts VALUES (?);', (tox_id, )) cursor.execute('CREATE TABLE IF NOT EXISTS id' + tox_id + '('
cursor.execute('CREATE TABLE id' + tox_id + '('
' id INTEGER PRIMARY KEY,' ' id INTEGER PRIMARY KEY,'
' message_id INTEGER,'
' author_name TEXT,' ' author_name TEXT,'
' message TEXT,' ' message TEXT,'
' author INTEGER,' ' author INTEGER,'
@ -94,7 +82,6 @@ class Database:
db = self._connect() db = self._connect()
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.execute('DELETE FROM contacts WHERE tox_id=?;', (tox_id, ))
cursor.execute('DROP TABLE id' + tox_id + ';') cursor.execute('DROP TABLE id' + tox_id + ';')
db.commit() db.commit()
except: except:
@ -103,20 +90,12 @@ class Database:
finally: finally:
db.close() db.close()
def friend_exists_in_db(self, tox_id):
db = self._connect()
cursor = db.cursor()
cursor.execute('SELECT 1 FROM contacts WHERE tox_id=?', (tox_id, ))
result = cursor.fetchone()
db.close()
return result is not None
def save_messages_to_db(self, tox_id, messages_iter): def save_messages_to_db(self, tox_id, messages_iter):
db = self._connect() db = self._connect()
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.executemany('INSERT INTO id' + tox_id + cursor.executemany('INSERT INTO id' + tox_id +
'(message, message_id, author_name, author, unix_time, message_type) ' + '(message, author_name, author, unix_time, message_type) ' +
'VALUES (?, ?, ?, ?, ?, ?);', messages_iter) 'VALUES (?, ?, ?, ?, ?, ?);', messages_iter)
db.commit() db.commit()
except: except:
@ -130,7 +109,7 @@ class Database:
try: try:
cursor = db.cursor() cursor = db.cursor()
cursor.execute('UPDATE id' + tox_id + ' SET author = 0 ' cursor.execute('UPDATE id' + tox_id + ' SET author = 0 '
'WHERE message_id = ' + str(message_id) + ' AND author = 2;') 'WHERE id = ' + str(message_id) + ' AND author = 2;')
db.commit() db.commit()
except: except:
print('Database is locked!') print('Database is locked!')
@ -163,8 +142,7 @@ class Database:
db.close() db.close()
def messages_getter(self, tox_id): def messages_getter(self, tox_id):
if not self.friend_exists_in_db(tox_id): self.add_friend_to_db(tox_id)
self.add_friend_to_db(tox_id)
return Database.MessageGetter(self._path, tox_id) return Database.MessageGetter(self._path, tox_id)
@ -180,15 +158,6 @@ class Database:
self._tox_id = tox_id self._tox_id = tox_id
self._db = self._cursor = None self._db = self._cursor = None
def _connect(self):
self._db = connect(self._path, timeout=TIMEOUT)
self._cursor = self._db.cursor()
self._cursor.execute('SELECT id, message_id, message, author, unix_time, message_type FROM id' +
self._tox_id + ' ORDER BY unix_time DESC;')
def _disconnect(self):
self._db.close()
def get_one(self): def get_one(self):
return self.get(1) return self.get(1)
@ -214,3 +183,19 @@ class Database:
def delete_one(self): def delete_one(self):
if self._count: if self._count:
self._count -= 1 self._count -= 1
def _connect(self):
self._db = connect(self._path, timeout=TIMEOUT)
self._cursor = self._db.cursor()
self._cursor.execute('SELECT id, message, author, unix_time, message_type FROM id' +
self._tox_id + ' ORDER BY unix_time DESC;')
def _disconnect(self):
self._db.close()
# -----------------------------------------------------------------------------------------------------------------
# Private methods
# -----------------------------------------------------------------------------------------------------------------
def _connect(self):
return connect(self._path, timeout=TIMEOUT)

View file

@ -1,14 +1,15 @@
from history.history_logs_generators import * from history.history_logs_generators import *
# TODO: fix history loading and saving
class History: class History:
def __init__(self, contact_provider, db, settings): def __init__(self, contact_provider, db, settings, main_screen, messages_items_factory):
self._contact_provider = contact_provider self._contact_provider = contact_provider
self._db = db self._db = db
self._settings = settings self._settings = settings
self._messages = main_screen.messages
self._messages_items_factory = messages_items_factory
self._is_loading = False
def __del__(self): def __del__(self):
del self._db del self._db
@ -23,8 +24,7 @@ class History:
""" """
if self._settings['save_db']: if self._settings['save_db']:
for friend in self._contact_provider.get_all_friends(): for friend in self._contact_provider.get_all_friends():
if not self._db.friend_exists_in_db(friend.tox_id): self._db.add_friend_to_db(friend.tox_id)
self._db.add_friend_to_db(friend.tox_id)
if not self._settings['save_unsent_only']: if not self._settings['save_unsent_only']:
messages = friend.get_corr_for_saving() messages = friend.get_corr_for_saving()
else: else:
@ -41,68 +41,50 @@ class History:
Clear chat history Clear chat history
""" """
friend.clear_corr(save_unsent) friend.clear_corr(save_unsent)
if self._db.friend_exists_in_db(friend.tox_id): self._db.delete_friend_from_db(friend.tox_id)
self._db.delete_messages(friend.tox_id)
self._db.delete_friend_from_db(friend.tox_id)
def delete_message(self, message): def delete_message(self, message):
pass pass
def load_history(self): def load_history(self, friend):
""" """
Tries to load next part of messages Tries to load next part of messages
""" """
if not self._load_db: if self._is_loading:
return return
self._load_db = False self._is_loading = True
friend = self.get_curr_friend()
friend.load_corr(False) friend.load_corr(False)
data = friend.get_corr() messages = friend.get_corr()
if not data: if not messages:
self._is_loading = False
return return
data.reverse() messages.reverse()
data = data[self._messages.count():self._messages.count() + PAGE_SIZE] messages = messages[self._messages.count():self._messages.count() + PAGE_SIZE]
for message in data: for message in messages:
if message.get_type() <= 1: # text message if message.get_type() <= 1: # text message
data = message.get_data() self._create_message_item(message)
self.create_message_item(data[0],
data[2],
data[1],
data[3],
False)
elif message.get_type() == MESSAGE_TYPE['FILE_TRANSFER']: # file transfer elif message.get_type() == MESSAGE_TYPE['FILE_TRANSFER']: # file transfer
if message.get_status() is None: if message.get_status() is None:
self.create_unsent_file_item(message) self._create_unsent_file_item(message)
continue continue
item = self.create_file_transfer_item(message, False) self._create_file_transfer_item(message)
if message.get_status() in ACTIVE_FILE_TRANSFERS: # active file transfer
try:
ft = self._file_transfers[(message.get_friend_number(), message.get_file_number())]
ft.set_state_changed_handler(item.update_transfer_state)
ft.signal()
except:
print('Incoming not started transfer - no info found')
elif message.get_type() == MESSAGE_TYPE['INLINE']: # inline image elif message.get_type() == MESSAGE_TYPE['INLINE']: # inline image
self.create_inline_item(message.get_data(), False) self._create_inline_item(message)
else: # info message else: # info message
data = message.get_data() self._create_message_item(message)
self.create_message_item(data[0], self._is_loading = False
data[2],
'',
data[3],
False)
self._load_db = True
def get_message_getter(self, friend_public_key): def get_message_getter(self, friend_public_key):
if not self._db.friend_exists_in_db(friend_public_key): self._db.add_friend_to_db(friend_public_key)
self._db.add_friend_to_db(friend_public_key)
return self._db.messages_getter(friend_public_key) return self._db.messages_getter(friend_public_key)
def delete_history(self, friend): def delete_history(self, friend):
self.clear_history(friend) self.clear_history(friend)
if self._db.friend_exists_in_db(friend.tox_id): self._db.delete_friend_from_db(friend.tox_id)
self._db.delete_friend_from_db(friend.tox_id)
def add_friend_to_db(self, tox_id):
self._db.add_friend_to_db(tox_id)
@staticmethod @staticmethod
def export_history(contact, as_text=True, _range=None): def export_history(contact, as_text=True, _range=None):
@ -117,3 +99,19 @@ class History:
generator = TextHistoryGenerator(corr, contact.name) if as_text else HtmlHistoryGenerator(corr, contact.name) generator = TextHistoryGenerator(corr, contact.name) if as_text else HtmlHistoryGenerator(corr, contact.name)
return generator.generate() return generator.generate()
# -----------------------------------------------------------------------------------------------------------------
# Items creation
# -----------------------------------------------------------------------------------------------------------------
def _create_message_item(self, message):
return self._messages_items_factory.create_message_item(message, False)
def _create_unsent_file_item(self, message):
return self._messages_items_factory.create_unsent_file_item(message, False)
def _create_file_transfer_item(self, message):
return self._messages_items_factory.create_file_transfer_item(message, False)
def _create_inline_item(self, message):
return self._messages_items_factory.create_inline_item(message, False)

100
toxygen/ui/contact_items.py Normal file
View file

@ -0,0 +1,100 @@
from wrapper.toxcore_enums_and_consts import *
from PyQt5 import QtCore, QtGui, QtWidgets
from contacts import profile
from file_transfers.file_transfers import TOX_FILE_TRANSFER_STATE, PAUSED_FILE_TRANSFERS, DO_NOT_SHOW_ACCEPT_BUTTON, ACTIVE_FILE_TRANSFERS, SHOW_PROGRESS_BAR
from utils.util import *
from ui.widgets import DataLabel, create_menu
from user_data import settings
class ContactItem(QtWidgets.QWidget):
"""
Contact in friends list
"""
def __init__(self, settings, parent=None):
QtWidgets.QWidget.__init__(self, parent)
mode = settings['compact_mode']
self.setBaseSize(QtCore.QSize(250, 40 if mode else 70))
self.avatar_label = QtWidgets.QLabel(self)
size = 32 if mode else 64
self.avatar_label.setGeometry(QtCore.QRect(3, 4, size, size))
self.avatar_label.setScaledContents(False)
self.avatar_label.setAlignment(QtCore.Qt.AlignCenter)
self.name = DataLabel(self)
self.name.setGeometry(QtCore.QRect(50 if mode else 75, 3 if mode else 10, 150, 15 if mode else 25))
font = QtGui.QFont()
font.setFamily(settings['font'])
font.setPointSize(10 if mode else 12)
font.setBold(True)
self.name.setFont(font)
self.status_message = DataLabel(self)
self.status_message.setGeometry(QtCore.QRect(50 if mode else 75, 20 if mode else 30, 170, 15 if mode else 20))
font.setPointSize(10)
font.setBold(False)
self.status_message.setFont(font)
self.connection_status = StatusCircle(self)
self.connection_status.setGeometry(QtCore.QRect(230, -2 if mode else 5, 32, 32))
self.messages = UnreadMessagesCount(settings, self)
self.messages.setGeometry(QtCore.QRect(20 if mode else 52, 20 if mode else 50, 30, 20))
class StatusCircle(QtWidgets.QWidget):
"""
Connection status
"""
def __init__(self, parent):
QtWidgets.QWidget.__init__(self, parent)
self.setGeometry(0, 0, 32, 32)
self.label = QtWidgets.QLabel(self)
self.label.setGeometry(QtCore.QRect(0, 0, 32, 32))
self.unread = False
def update(self, status, unread_messages=None):
if unread_messages is None:
unread_messages = self.unread
else:
self.unread = unread_messages
if status == TOX_USER_STATUS['NONE']:
name = 'online'
elif status == TOX_USER_STATUS['AWAY']:
name = 'idle'
elif status == TOX_USER_STATUS['BUSY']:
name = 'busy'
else:
name = 'offline'
if unread_messages:
name += '_notification'
self.label.setGeometry(QtCore.QRect(0, 0, 32, 32))
else:
self.label.setGeometry(QtCore.QRect(2, 0, 32, 32))
pixmap = QtGui.QPixmap(join_path(get_images_directory(), '{}.png'.format(name)))
self.label.setPixmap(pixmap)
class UnreadMessagesCount(QtWidgets.QWidget):
def __init__(self, settings, parent=None):
super().__init__(parent)
self._settings = settings
self.resize(30, 20)
self.label = QtWidgets.QLabel(self)
self.label.setGeometry(QtCore.QRect(0, 0, 30, 20))
self.label.setVisible(False)
font = QtGui.QFont()
font.setFamily(settings['font'])
font.setPointSize(12)
font.setBold(True)
self.label.setFont(font)
self.label.setAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)
color = settings['unread_color']
self.label.setStyleSheet('QLabel { color: white; background-color: ' + color + '; border-radius: 10; }')
def update(self, messages_count):
color = self._settings['unread_color']
self.label.setStyleSheet('QLabel { color: white; background-color: ' + color + '; border-radius: 10; }')
if messages_count:
self.label.setVisible(True)
self.label.setText(str(messages_count))
else:
self.label.setVisible(False)

View file

@ -1,4 +1,4 @@
from ui.list_items import * from ui.contact_items import *
from ui.messages_widgets import * from ui.messages_widgets import *
@ -18,17 +18,19 @@ class FriendItemsFactory:
return item return item
# TODO: accept messages everywhere instead of params
class MessagesItemsFactory: class MessagesItemsFactory:
def __init__(self, settings, plugin_loader, smiley_loader, main_screen, history): def __init__(self, settings, plugin_loader, smiley_loader, main_screen, delete_action):
self._settings, self._plugin_loader = settings, plugin_loader self._settings, self._plugin_loader = settings, plugin_loader
self._smiley_loader, self._history = smiley_loader, history self._smiley_loader, self._delete_action = smiley_loader, delete_action
self._messages = main_screen.messages self._messages = main_screen.messages
self._message_edit = main_screen.messageEdit self._message_edit = main_screen.messageEdit
def create_message_item(self, message, append=True, pixmap=None): def create_message_item(self, message, append=True, pixmap=None):
item = message.get_widget(self._settings, self._create_message_browser, item = message.get_widget(self._settings, self._create_message_browser,
self._history.delete_message, self._messages) self._delete_action, self._messages)
if pixmap is not None: if pixmap is not None:
item.set_avatar(pixmap) item.set_avatar(pixmap)
elem = QtWidgets.QListWidgetItem() elem = QtWidgets.QListWidgetItem()
@ -69,7 +71,7 @@ class MessagesItemsFactory:
return item return item
def create_file_transfer_item(self, data, append): def create_file_transfer_item(self, data, append=True):
data.append(self._messages.width()) data.append(self._messages.width())
item = FileTransferItem(*data) item = FileTransferItem(*data)
elem = QtWidgets.QListWidgetItem() elem = QtWidgets.QListWidgetItem()

View file

@ -1,343 +0,0 @@
from wrapper.toxcore_enums_and_consts import *
from PyQt5 import QtCore, QtGui, QtWidgets
from contacts import profile
from file_transfers.file_transfers import TOX_FILE_TRANSFER_STATE, PAUSED_FILE_TRANSFERS, DO_NOT_SHOW_ACCEPT_BUTTON, ACTIVE_FILE_TRANSFERS, SHOW_PROGRESS_BAR
from utils.util import *
from ui.widgets import DataLabel, create_menu
from user_data import settings
class ContactItem(QtWidgets.QWidget):
"""
Contact in friends list
"""
def __init__(self, settings, parent=None):
QtWidgets.QWidget.__init__(self, parent)
mode = settings['compact_mode']
self.setBaseSize(QtCore.QSize(250, 40 if mode else 70))
self.avatar_label = QtWidgets.QLabel(self)
size = 32 if mode else 64
self.avatar_label.setGeometry(QtCore.QRect(3, 4, size, size))
self.avatar_label.setScaledContents(False)
self.avatar_label.setAlignment(QtCore.Qt.AlignCenter)
self.name = DataLabel(self)
self.name.setGeometry(QtCore.QRect(50 if mode else 75, 3 if mode else 10, 150, 15 if mode else 25))
font = QtGui.QFont()
font.setFamily(settings['font'])
font.setPointSize(10 if mode else 12)
font.setBold(True)
self.name.setFont(font)
self.status_message = DataLabel(self)
self.status_message.setGeometry(QtCore.QRect(50 if mode else 75, 20 if mode else 30, 170, 15 if mode else 20))
font.setPointSize(10)
font.setBold(False)
self.status_message.setFont(font)
self.connection_status = StatusCircle(self)
self.connection_status.setGeometry(QtCore.QRect(230, -2 if mode else 5, 32, 32))
self.messages = UnreadMessagesCount(settings, self)
self.messages.setGeometry(QtCore.QRect(20 if mode else 52, 20 if mode else 50, 30, 20))
class StatusCircle(QtWidgets.QWidget):
"""
Connection status
"""
def __init__(self, parent):
QtWidgets.QWidget.__init__(self, parent)
self.setGeometry(0, 0, 32, 32)
self.label = QtWidgets.QLabel(self)
self.label.setGeometry(QtCore.QRect(0, 0, 32, 32))
self.unread = False
def update(self, status, unread_messages=None):
if unread_messages is None:
unread_messages = self.unread
else:
self.unread = unread_messages
if status == TOX_USER_STATUS['NONE']:
name = 'online'
elif status == TOX_USER_STATUS['AWAY']:
name = 'idle'
elif status == TOX_USER_STATUS['BUSY']:
name = 'busy'
else:
name = 'offline'
if unread_messages:
name += '_notification'
self.label.setGeometry(QtCore.QRect(0, 0, 32, 32))
else:
self.label.setGeometry(QtCore.QRect(2, 0, 32, 32))
pixmap = QtGui.QPixmap(join_path(get_images_directory(), '{}.png'.format(name)))
self.label.setPixmap(pixmap)
class UnreadMessagesCount(QtWidgets.QWidget):
def __init__(self, settings, parent=None):
super().__init__(parent)
self._settings = settings
self.resize(30, 20)
self.label = QtWidgets.QLabel(self)
self.label.setGeometry(QtCore.QRect(0, 0, 30, 20))
self.label.setVisible(False)
font = QtGui.QFont()
font.setFamily(settings['font'])
font.setPointSize(12)
font.setBold(True)
self.label.setFont(font)
self.label.setAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)
color = settings['unread_color']
self.label.setStyleSheet('QLabel { color: white; background-color: ' + color + '; border-radius: 10; }')
def update(self, messages_count):
color = self._settings['unread_color']
self.label.setStyleSheet('QLabel { color: white; background-color: ' + color + '; border-radius: 10; }')
if messages_count:
self.label.setVisible(True)
self.label.setText(str(messages_count))
else:
self.label.setVisible(False)
class FileTransferItem(QtWidgets.QListWidget):
def __init__(self, file_name, size, time, user, friend_number, file_number, state, width, parent=None):
QtWidgets.QListWidget.__init__(self, parent)
self.resize(QtCore.QSize(width, 34))
if state == TOX_FILE_TRANSFER_STATE['CANCELLED']:
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
elif state in PAUSED_FILE_TRANSFERS:
self.setStyleSheet('QListWidget { border: 1px solid #FF8000; }')
else:
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.name = DataLabel(self)
self.name.setGeometry(QtCore.QRect(3, 7, 95, 25))
self.name.setTextFormat(QtCore.Qt.PlainText)
font = QtGui.QFont()
# FIXME
font.setFamily(settings.Settings.get_instance()['font'])
font.setPointSize(11)
font.setBold(True)
self.name.setFont(font)
self.name.setText(user)
self.time = QtWidgets.QLabel(self)
self.time.setGeometry(QtCore.QRect(width - 60, 7, 50, 25))
font.setPointSize(10)
font.setBold(False)
self.time.setFont(font)
self.time.setText(convert_time(time))
self.cancel = QtWidgets.QPushButton(self)
self.cancel.setGeometry(QtCore.QRect(width - 125, 2, 30, 30))
pixmap = QtGui.QPixmap(curr_directory() + '/images/decline.png')
icon = QtGui.QIcon(pixmap)
self.cancel.setIcon(icon)
self.cancel.setIconSize(QtCore.QSize(30, 30))
self.cancel.setVisible(state in ACTIVE_FILE_TRANSFERS)
self.cancel.clicked.connect(lambda: self.cancel_transfer(friend_number, file_number))
self.cancel.setStyleSheet('QPushButton:hover { border: 1px solid #3A3939; background-color: none;}')
self.accept_or_pause = QtWidgets.QPushButton(self)
self.accept_or_pause.setGeometry(QtCore.QRect(width - 170, 2, 30, 30))
if state == TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED']:
self.accept_or_pause.setVisible(True)
self.button_update('accept')
elif state in DO_NOT_SHOW_ACCEPT_BUTTON:
self.accept_or_pause.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']: # setup for continue
self.accept_or_pause.setVisible(True)
self.button_update('resume')
else: # pause
self.accept_or_pause.setVisible(True)
self.button_update('pause')
self.accept_or_pause.clicked.connect(lambda: self.accept_or_pause_transfer(friend_number, file_number, size))
self.accept_or_pause.setStyleSheet('QPushButton:hover { border: 1px solid #3A3939; background-color: none}')
self.pb = QtWidgets.QProgressBar(self)
self.pb.setGeometry(QtCore.QRect(100, 7, 100, 20))
self.pb.setValue(0)
self.pb.setStyleSheet('QProgressBar { background-color: #302F2F; }')
self.pb.setVisible(state in SHOW_PROGRESS_BAR)
self.file_name = DataLabel(self)
self.file_name.setGeometry(QtCore.QRect(210, 7, width - 420, 20))
font.setPointSize(12)
self.file_name.setFont(font)
file_size = size // 1024
if not file_size:
file_size = '{}B'.format(size)
elif file_size >= 1024:
file_size = '{}MB'.format(file_size // 1024)
else:
file_size = '{}KB'.format(file_size)
file_data = '{} {}'.format(file_size, file_name)
self.file_name.setText(file_data)
self.file_name.setToolTip(file_name)
self.saved_name = file_name
self.time_left = QtWidgets.QLabel(self)
self.time_left.setGeometry(QtCore.QRect(width - 92, 7, 30, 20))
font.setPointSize(10)
self.time_left.setFont(font)
self.time_left.setVisible(state == TOX_FILE_TRANSFER_STATE['RUNNING'])
self.setFocusPolicy(QtCore.Qt.NoFocus)
self.paused = False
def cancel_transfer(self, friend_number, file_number):
pr = profile.Profile.get_instance()
pr.cancel_transfer(friend_number, file_number)
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
self.cancel.setVisible(False)
self.accept_or_pause.setVisible(False)
self.pb.setVisible(False)
def accept_or_pause_transfer(self, friend_number, file_number, size):
if self.state == TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED']:
directory = QtWidgets.QFileDialog.getExistingDirectory(self,
QtWidgets.QApplication.translate("MainWindow", 'Choose folder'),
curr_directory(),
QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog)
self.pb.setVisible(True)
if directory:
pr = profile.Profile.get_instance()
pr.accept_transfer(self, directory + '/' + self.saved_name, friend_number, file_number, size)
self.button_update('pause')
elif self.state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']: # resume
self.paused = False
profile.Profile.get_instance().resume_transfer(friend_number, file_number)
self.button_update('pause')
self.state = TOX_FILE_TRANSFER_STATE['RUNNING']
else: # pause
self.paused = True
self.state = TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']
profile.Profile.get_instance().pause_transfer(friend_number, file_number)
self.button_update('resume')
self.accept_or_pause.clearFocus()
def button_update(self, path):
pixmap = QtGui.QPixmap(curr_directory() + '/images/{}.png'.format(path))
icon = QtGui.QIcon(pixmap)
self.accept_or_pause.setIcon(icon)
self.accept_or_pause.setIconSize(QtCore.QSize(30, 30))
def update_transfer_state(self, state, progress, time):
self.pb.setValue(int(progress * 100))
if time + 1:
m, s = divmod(time, 60)
self.time_left.setText('{0:02d}:{1:02d}'.format(m, s))
if self.state != state and self.state in ACTIVE_FILE_TRANSFERS:
if state == TOX_FILE_TRANSFER_STATE['CANCELLED']:
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
self.cancel.setVisible(False)
self.accept_or_pause.setVisible(False)
self.pb.setVisible(False)
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['FINISHED']:
self.accept_or_pause.setVisible(False)
self.pb.setVisible(False)
self.cancel.setVisible(False)
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_FRIEND']:
self.accept_or_pause.setVisible(False)
self.setStyleSheet('QListWidget { border: 1px solid #FF8000; }')
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']:
self.button_update('resume') # setup button continue
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED']:
self.setStyleSheet('QListWidget { border: 1px solid #FF8000; }')
self.accept_or_pause.setVisible(False)
self.time_left.setVisible(False)
self.pb.setVisible(False)
elif not self.paused: # active
self.pb.setVisible(True)
self.accept_or_pause.setVisible(True) # setup to pause
self.button_update('pause')
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.time_left.setVisible(True)
def mark_as_sent(self):
return False
class UnsentFileItem(FileTransferItem):
def __init__(self, file_name, size, user, time, width, parent=None):
super(UnsentFileItem, self).__init__(file_name, size, time, user, -1, -1,
TOX_FILE_TRANSFER_STATE['PAUSED_BY_FRIEND'], width, parent)
self._time = time
self.pb.setVisible(False)
movie = QtGui.QMovie(join_path(get_images_directory(), 'spinner.gif'))
self.time.setMovie(movie)
movie.start()
def cancel_transfer(self, *args):
pr = profile.Profile.get_instance()
pr.cancel_not_started_transfer(self._time)
class InlineImageItem(QtWidgets.QScrollArea):
def __init__(self, data, width, elem):
QtWidgets.QScrollArea.__init__(self)
self.setFocusPolicy(QtCore.Qt.NoFocus)
self._elem = elem
self._image_label = QtWidgets.QLabel(self)
self._image_label.raise_()
self.setWidget(self._image_label)
self._image_label.setScaledContents(False)
self._pixmap = QtGui.QPixmap()
self._pixmap.loadFromData(data, 'PNG')
self._max_size = width - 30
self._resize_needed = not (self._pixmap.width() <= self._max_size)
self._full_size = not self._resize_needed
if not self._resize_needed:
self._image_label.setPixmap(self._pixmap)
self.resize(QtCore.QSize(self._max_size + 5, self._pixmap.height() + 5))
self._image_label.setGeometry(5, 0, self._pixmap.width(), self._pixmap.height())
else:
pixmap = self._pixmap.scaled(self._max_size, self._max_size, QtCore.Qt.KeepAspectRatio)
self._image_label.setPixmap(pixmap)
self.resize(QtCore.QSize(self._max_size + 5, pixmap.height()))
self._image_label.setGeometry(5, 0, self._max_size + 5, pixmap.height())
self._elem.setSizeHint(QtCore.QSize(self.width(), self.height()))
def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self._resize_needed: # scale inline
if self._full_size:
pixmap = self._pixmap.scaled(self._max_size, self._max_size, QtCore.Qt.KeepAspectRatio)
self._image_label.setPixmap(pixmap)
self.resize(QtCore.QSize(self._max_size, pixmap.height()))
self._image_label.setGeometry(5, 0, pixmap.width(), pixmap.height())
else:
self._image_label.setPixmap(self._pixmap)
self.resize(QtCore.QSize(self._max_size, self._pixmap.height() + 17))
self._image_label.setGeometry(5, 0, self._pixmap.width(), self._pixmap.height())
self._full_size = not self._full_size
self._elem.setSizeHint(QtCore.QSize(self.width(), self.height()))
elif event.button() == QtCore.Qt.RightButton: # save inline
# TODO: dialog
directory = QtWidgets.QFileDialog.getExistingDirectory(self,
QtWidgets.QApplication.translate("MainWindow",
'Choose folder'),
curr_directory(),
QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog)
if directory:
fl = QtCore.QFile(directory + '/toxygen_inline_' + curr_time().replace(':', '_') + '.png')
self._pixmap.save(fl, 'PNG')
def mark_as_sent(self):
return False

View file

@ -1,5 +1,5 @@
from contacts.profile import * from contacts.profile import *
from ui.list_items import * from ui.contact_items import *
from ui.widgets import MultilineEdit, ComboBox from ui.widgets import MultilineEdit, ComboBox
from ui.main_screen_widgets import * from ui.main_screen_widgets import *
import utils.util as util import utils.util as util

View file

@ -213,3 +213,245 @@ class MessageItem(QtWidgets.QWidget):
i += len(sub) i += len(sub)
return text return text
class FileTransferItem(QtWidgets.QListWidget):
def __init__(self, file_name, size, time, user, friend_number, file_number, state, width, parent=None):
QtWidgets.QListWidget.__init__(self, parent)
self.resize(QtCore.QSize(width, 34))
if state == TOX_FILE_TRANSFER_STATE['CANCELLED']:
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
elif state in PAUSED_FILE_TRANSFERS:
self.setStyleSheet('QListWidget { border: 1px solid #FF8000; }')
else:
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.name = DataLabel(self)
self.name.setGeometry(QtCore.QRect(3, 7, 95, 25))
self.name.setTextFormat(QtCore.Qt.PlainText)
font = QtGui.QFont()
# FIXME
font.setFamily(settings.Settings.get_instance()['font'])
font.setPointSize(11)
font.setBold(True)
self.name.setFont(font)
self.name.setText(user)
self.time = QtWidgets.QLabel(self)
self.time.setGeometry(QtCore.QRect(width - 60, 7, 50, 25))
font.setPointSize(10)
font.setBold(False)
self.time.setFont(font)
self.time.setText(convert_time(time))
self.cancel = QtWidgets.QPushButton(self)
self.cancel.setGeometry(QtCore.QRect(width - 125, 2, 30, 30))
pixmap = QtGui.QPixmap(curr_directory() + '/images/decline.png')
icon = QtGui.QIcon(pixmap)
self.cancel.setIcon(icon)
self.cancel.setIconSize(QtCore.QSize(30, 30))
self.cancel.setVisible(state in ACTIVE_FILE_TRANSFERS)
self.cancel.clicked.connect(lambda: self.cancel_transfer(friend_number, file_number))
self.cancel.setStyleSheet('QPushButton:hover { border: 1px solid #3A3939; background-color: none;}')
self.accept_or_pause = QtWidgets.QPushButton(self)
self.accept_or_pause.setGeometry(QtCore.QRect(width - 170, 2, 30, 30))
if state == TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED']:
self.accept_or_pause.setVisible(True)
self.button_update('accept')
elif state in DO_NOT_SHOW_ACCEPT_BUTTON:
self.accept_or_pause.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']: # setup for continue
self.accept_or_pause.setVisible(True)
self.button_update('resume')
else: # pause
self.accept_or_pause.setVisible(True)
self.button_update('pause')
self.accept_or_pause.clicked.connect(lambda: self.accept_or_pause_transfer(friend_number, file_number, size))
self.accept_or_pause.setStyleSheet('QPushButton:hover { border: 1px solid #3A3939; background-color: none}')
self.pb = QtWidgets.QProgressBar(self)
self.pb.setGeometry(QtCore.QRect(100, 7, 100, 20))
self.pb.setValue(0)
self.pb.setStyleSheet('QProgressBar { background-color: #302F2F; }')
self.pb.setVisible(state in SHOW_PROGRESS_BAR)
self.file_name = DataLabel(self)
self.file_name.setGeometry(QtCore.QRect(210, 7, width - 420, 20))
font.setPointSize(12)
self.file_name.setFont(font)
file_size = size // 1024
if not file_size:
file_size = '{}B'.format(size)
elif file_size >= 1024:
file_size = '{}MB'.format(file_size // 1024)
else:
file_size = '{}KB'.format(file_size)
file_data = '{} {}'.format(file_size, file_name)
self.file_name.setText(file_data)
self.file_name.setToolTip(file_name)
self.saved_name = file_name
self.time_left = QtWidgets.QLabel(self)
self.time_left.setGeometry(QtCore.QRect(width - 92, 7, 30, 20))
font.setPointSize(10)
self.time_left.setFont(font)
self.time_left.setVisible(state == TOX_FILE_TRANSFER_STATE['RUNNING'])
self.setFocusPolicy(QtCore.Qt.NoFocus)
self.paused = False
def cancel_transfer(self, friend_number, file_number):
pr = profile.Profile.get_instance()
pr.cancel_transfer(friend_number, file_number)
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
self.cancel.setVisible(False)
self.accept_or_pause.setVisible(False)
self.pb.setVisible(False)
def accept_or_pause_transfer(self, friend_number, file_number, size):
if self.state == TOX_FILE_TRANSFER_STATE['INCOMING_NOT_STARTED']:
directory = QtWidgets.QFileDialog.getExistingDirectory(self,
QtWidgets.QApplication.translate("MainWindow", 'Choose folder'),
curr_directory(),
QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog)
self.pb.setVisible(True)
if directory:
pr = profile.Profile.get_instance()
pr.accept_transfer(self, directory + '/' + self.saved_name, friend_number, file_number, size)
self.button_update('pause')
elif self.state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']: # resume
self.paused = False
profile.Profile.get_instance().resume_transfer(friend_number, file_number)
self.button_update('pause')
self.state = TOX_FILE_TRANSFER_STATE['RUNNING']
else: # pause
self.paused = True
self.state = TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']
profile.Profile.get_instance().pause_transfer(friend_number, file_number)
self.button_update('resume')
self.accept_or_pause.clearFocus()
def button_update(self, path):
pixmap = QtGui.QPixmap(curr_directory() + '/images/{}.png'.format(path))
icon = QtGui.QIcon(pixmap)
self.accept_or_pause.setIcon(icon)
self.accept_or_pause.setIconSize(QtCore.QSize(30, 30))
def update_transfer_state(self, state, progress, time):
self.pb.setValue(int(progress * 100))
if time + 1:
m, s = divmod(time, 60)
self.time_left.setText('{0:02d}:{1:02d}'.format(m, s))
if self.state != state and self.state in ACTIVE_FILE_TRANSFERS:
if state == TOX_FILE_TRANSFER_STATE['CANCELLED']:
self.setStyleSheet('QListWidget { border: 1px solid #B40404; }')
self.cancel.setVisible(False)
self.accept_or_pause.setVisible(False)
self.pb.setVisible(False)
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['FINISHED']:
self.accept_or_pause.setVisible(False)
self.pb.setVisible(False)
self.cancel.setVisible(False)
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_FRIEND']:
self.accept_or_pause.setVisible(False)
self.setStyleSheet('QListWidget { border: 1px solid #FF8000; }')
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['PAUSED_BY_USER']:
self.button_update('resume') # setup button continue
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.time_left.setVisible(False)
elif state == TOX_FILE_TRANSFER_STATE['OUTGOING_NOT_STARTED']:
self.setStyleSheet('QListWidget { border: 1px solid #FF8000; }')
self.accept_or_pause.setVisible(False)
self.time_left.setVisible(False)
self.pb.setVisible(False)
elif not self.paused: # active
self.pb.setVisible(True)
self.accept_or_pause.setVisible(True) # setup to pause
self.button_update('pause')
self.setStyleSheet('QListWidget { border: 1px solid green; }')
self.state = state
self.time_left.setVisible(True)
def mark_as_sent(self):
return False
class UnsentFileItem(FileTransferItem):
def __init__(self, file_name, size, user, time, width, parent=None):
super(UnsentFileItem, self).__init__(file_name, size, time, user, -1, -1,
TOX_FILE_TRANSFER_STATE['PAUSED_BY_FRIEND'], width, parent)
self._time = time
self.pb.setVisible(False)
movie = QtGui.QMovie(join_path(get_images_directory(), 'spinner.gif'))
self.time.setMovie(movie)
movie.start()
def cancel_transfer(self, *args):
pr = profile.Profile.get_instance()
pr.cancel_not_started_transfer(self._time)
class InlineImageItem(QtWidgets.QScrollArea):
def __init__(self, data, width, elem):
QtWidgets.QScrollArea.__init__(self)
self.setFocusPolicy(QtCore.Qt.NoFocus)
self._elem = elem
self._image_label = QtWidgets.QLabel(self)
self._image_label.raise_()
self.setWidget(self._image_label)
self._image_label.setScaledContents(False)
self._pixmap = QtGui.QPixmap()
self._pixmap.loadFromData(data, 'PNG')
self._max_size = width - 30
self._resize_needed = not (self._pixmap.width() <= self._max_size)
self._full_size = not self._resize_needed
if not self._resize_needed:
self._image_label.setPixmap(self._pixmap)
self.resize(QtCore.QSize(self._max_size + 5, self._pixmap.height() + 5))
self._image_label.setGeometry(5, 0, self._pixmap.width(), self._pixmap.height())
else:
pixmap = self._pixmap.scaled(self._max_size, self._max_size, QtCore.Qt.KeepAspectRatio)
self._image_label.setPixmap(pixmap)
self.resize(QtCore.QSize(self._max_size + 5, pixmap.height()))
self._image_label.setGeometry(5, 0, self._max_size + 5, pixmap.height())
self._elem.setSizeHint(QtCore.QSize(self.width(), self.height()))
def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self._resize_needed: # scale inline
if self._full_size:
pixmap = self._pixmap.scaled(self._max_size, self._max_size, QtCore.Qt.KeepAspectRatio)
self._image_label.setPixmap(pixmap)
self.resize(QtCore.QSize(self._max_size, pixmap.height()))
self._image_label.setGeometry(5, 0, pixmap.width(), pixmap.height())
else:
self._image_label.setPixmap(self._pixmap)
self.resize(QtCore.QSize(self._max_size, self._pixmap.height() + 17))
self._image_label.setGeometry(5, 0, self._pixmap.width(), self._pixmap.height())
self._full_size = not self._full_size
self._elem.setSizeHint(QtCore.QSize(self.width(), self.height()))
elif event.button() == QtCore.Qt.RightButton: # save inline
# TODO: dialog
directory = QtWidgets.QFileDialog.getExistingDirectory(self,
QtWidgets.QApplication.translate("MainWindow",
'Choose folder'),
curr_directory(),
QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog)
if directory:
fl = QtCore.QFile(directory + '/toxygen_inline_' + curr_time().replace(':', '_') + '.png')
self._pixmap.save(fl, 'PNG')
def mark_as_sent(self):
return False