Address Tree updates
The Address tree now is sorted and updates when number of unread messages changes.
This commit is contained in:
parent
8d7fefe0e6
commit
f2d1bd8c2f
|
@ -6,6 +6,21 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
MessagingMenu = None
|
MessagingMenu = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
from PyQt4.QtCore import *
|
||||||
|
from PyQt4.QtGui import *
|
||||||
|
|
||||||
|
except Exception as err:
|
||||||
|
print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).'
|
||||||
|
print 'Error message:', err
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
try:
|
||||||
|
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||||
|
except AttributeError:
|
||||||
|
print 'QtGui.QApplication.UnicodeUTF8 error:', err
|
||||||
|
|
||||||
from addresses import *
|
from addresses import *
|
||||||
import shared
|
import shared
|
||||||
from bitmessageui import *
|
from bitmessageui import *
|
||||||
|
@ -13,6 +28,7 @@ from namecoin import namecoinConnection, ensureNamecoinOptions
|
||||||
from newaddressdialog import *
|
from newaddressdialog import *
|
||||||
from newaddresswizard import *
|
from newaddresswizard import *
|
||||||
from migrationwizard import *
|
from migrationwizard import *
|
||||||
|
from foldertree import *
|
||||||
from addaddressdialog import *
|
from addaddressdialog import *
|
||||||
from newsubscriptiondialog import *
|
from newsubscriptiondialog import *
|
||||||
from regenerateaddresses import *
|
from regenerateaddresses import *
|
||||||
|
@ -38,125 +54,12 @@ import subprocess
|
||||||
import datetime
|
import datetime
|
||||||
from helper_sql import *
|
from helper_sql import *
|
||||||
import l10n
|
import l10n
|
||||||
|
from utils import *
|
||||||
try:
|
from collections import OrderedDict
|
||||||
from PyQt4 import QtCore, QtGui
|
|
||||||
from PyQt4.QtCore import *
|
|
||||||
from PyQt4.QtGui import *
|
|
||||||
|
|
||||||
except Exception as err:
|
|
||||||
print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).'
|
|
||||||
print 'Error message:', err
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
try:
|
|
||||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
|
||||||
except AttributeError:
|
|
||||||
print 'QtGui.QApplication.UnicodeUTF8 error:', err
|
|
||||||
|
|
||||||
def _translate(context, text):
|
def _translate(context, text):
|
||||||
return QtGui.QApplication.translate(context, text)
|
return QtGui.QApplication.translate(context, text)
|
||||||
|
|
||||||
|
|
||||||
def identiconize(address):
|
|
||||||
size = 48
|
|
||||||
|
|
||||||
# If you include another identicon library, please generate an
|
|
||||||
# example identicon with the following md5 hash:
|
|
||||||
# 3fd4bf901b9d4ea1394f0fb358725b28
|
|
||||||
|
|
||||||
try:
|
|
||||||
identicon_lib = shared.config.get('bitmessagesettings', 'identiconlib')
|
|
||||||
except:
|
|
||||||
# default to qidenticon_two_x
|
|
||||||
identicon_lib = 'qidenticon_two_x'
|
|
||||||
|
|
||||||
# As an 'identiconsuffix' you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators. (Note however, that E-Mail programs might convert the BM-address to lowercase first.)
|
|
||||||
# It can be used as a pseudo-password to salt the generation of the identicons to decrease the risk
|
|
||||||
# of attacks where someone creates an address to mimic someone else's identicon.
|
|
||||||
identiconsuffix = shared.config.get('bitmessagesettings', 'identiconsuffix')
|
|
||||||
|
|
||||||
if not shared.config.getboolean('bitmessagesettings', 'useidenticons'):
|
|
||||||
idcon = QtGui.QIcon()
|
|
||||||
return idcon
|
|
||||||
|
|
||||||
if (identicon_lib[:len('qidenticon')] == 'qidenticon'):
|
|
||||||
# print identicon_lib
|
|
||||||
# originally by:
|
|
||||||
# :Author:Shin Adachi <shn@glucose.jp>
|
|
||||||
# Licesensed under FreeBSD License.
|
|
||||||
# stripped from PIL and uses QT instead (by sendiulo, same license)
|
|
||||||
import qidenticon
|
|
||||||
hash = hashlib.md5(addBMIfNotPresent(address)+identiconsuffix).hexdigest()
|
|
||||||
use_two_colors = (identicon_lib[:len('qidenticon_two')] == 'qidenticon_two')
|
|
||||||
opacity = int(not((identicon_lib == 'qidenticon_x') | (identicon_lib == 'qidenticon_two_x') | (identicon_lib == 'qidenticon_b') | (identicon_lib == 'qidenticon_two_b')))*255
|
|
||||||
penwidth = 0
|
|
||||||
image = qidenticon.render_identicon(int(hash, 16), size, use_two_colors, opacity, penwidth)
|
|
||||||
# filename = './images/identicons/'+hash+'.png'
|
|
||||||
# image.save(filename)
|
|
||||||
idcon = QtGui.QIcon()
|
|
||||||
idcon.addPixmap(image, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
return idcon
|
|
||||||
elif identicon_lib == 'pydenticon':
|
|
||||||
# print identicon_lib
|
|
||||||
# Here you could load pydenticon.py (just put it in the "src" folder of your Bitmessage source)
|
|
||||||
from pydenticon import Pydenticon
|
|
||||||
# It is not included in the source, because it is licensed under GPLv3
|
|
||||||
# GPLv3 is a copyleft license that would influence our licensing
|
|
||||||
# Find the source here: http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py
|
|
||||||
# note that it requires PIL to be installed: http://www.pythonware.com/products/pil/
|
|
||||||
idcon_render = Pydenticon(addBMIfNotPresent(address)+identiconsuffix, size*3)
|
|
||||||
rendering = idcon_render._render()
|
|
||||||
data = rendering.convert("RGBA").tostring("raw", "RGBA")
|
|
||||||
qim = QImage(data, size, size, QImage.Format_ARGB32)
|
|
||||||
pix = QPixmap.fromImage(qim)
|
|
||||||
idcon = QtGui.QIcon()
|
|
||||||
idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
return idcon
|
|
||||||
|
|
||||||
def avatarize(address):
|
|
||||||
"""
|
|
||||||
loads a supported image for the given address' hash form 'avatars' folder
|
|
||||||
falls back to default avatar if 'default.*' file exists
|
|
||||||
falls back to identiconize(address)
|
|
||||||
"""
|
|
||||||
idcon = QtGui.QIcon()
|
|
||||||
hash = hashlib.md5(addBMIfNotPresent(address)).hexdigest()
|
|
||||||
str_broadcast_subscribers = '[Broadcast subscribers]'
|
|
||||||
if address == str_broadcast_subscribers:
|
|
||||||
# don't hash [Broadcast subscribers]
|
|
||||||
hash = address
|
|
||||||
# http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats
|
|
||||||
# print QImageReader.supportedImageFormats ()
|
|
||||||
# QImageReader.supportedImageFormats ()
|
|
||||||
extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
|
|
||||||
# try to find a specific avatar
|
|
||||||
for ext in extensions:
|
|
||||||
lower_hash = shared.appdata + 'avatars/' + hash + '.' + ext.lower()
|
|
||||||
upper_hash = shared.appdata + 'avatars/' + hash + '.' + ext.upper()
|
|
||||||
if os.path.isfile(lower_hash):
|
|
||||||
# print 'found avatar of ', address
|
|
||||||
idcon.addFile(lower_hash)
|
|
||||||
return idcon
|
|
||||||
elif os.path.isfile(upper_hash):
|
|
||||||
# print 'found avatar of ', address
|
|
||||||
idcon.addFile(upper_hash)
|
|
||||||
return idcon
|
|
||||||
# if we haven't found any, try to find a default avatar
|
|
||||||
for ext in extensions:
|
|
||||||
lower_default = shared.appdata + 'avatars/' + 'default.' + ext.lower()
|
|
||||||
upper_default = shared.appdata + 'avatars/' + 'default.' + ext.upper()
|
|
||||||
if os.path.isfile(lower_default):
|
|
||||||
default = lower_default
|
|
||||||
idcon.addFile(lower_default)
|
|
||||||
return idcon
|
|
||||||
elif os.path.isfile(upper_default):
|
|
||||||
default = upper_default
|
|
||||||
idcon.addFile(upper_default)
|
|
||||||
return idcon
|
|
||||||
# If no avatar is found
|
|
||||||
return identiconize(address)
|
|
||||||
|
|
||||||
def change_translation(locale):
|
def change_translation(locale):
|
||||||
global qtranslator
|
global qtranslator
|
||||||
qtranslator = QtCore.QTranslator()
|
qtranslator = QtCore.QTranslator()
|
||||||
|
@ -168,29 +71,6 @@ def change_translation(locale):
|
||||||
qtranslator.load(translationpath)
|
qtranslator.load(translationpath)
|
||||||
QtGui.QApplication.installTranslator(qtranslator)
|
QtGui.QApplication.installTranslator(qtranslator)
|
||||||
|
|
||||||
def address_compare(x, y):
|
|
||||||
if x == "bitmessagesettings":
|
|
||||||
return -1
|
|
||||||
elif y == "bitmessagesettings":
|
|
||||||
return 1
|
|
||||||
if shared.config.getboolean(x, 'enabled') == shared.config.getboolean(y, 'enabled'):
|
|
||||||
if shared.config.get(x, 'label'):
|
|
||||||
x1 = shared.config.get(x, 'label').decode('utf-8').lower()
|
|
||||||
else:
|
|
||||||
x1 = x.decode('utf-8').lower()
|
|
||||||
if shared.config.get(y, 'label'):
|
|
||||||
y1 = shared.config.get(y, 'label').decode('utf-8').lower()
|
|
||||||
else:
|
|
||||||
y1 = y.decode('utf-8').lower()
|
|
||||||
if x1 > y1:
|
|
||||||
return 1
|
|
||||||
elif x1 < y1:
|
|
||||||
return -1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
return (-1 if shared.config.getboolean(x, 'enabled') else 1)
|
|
||||||
|
|
||||||
class MyForm(QtGui.QMainWindow):
|
class MyForm(QtGui.QMainWindow):
|
||||||
|
|
||||||
# sound type constants
|
# sound type constants
|
||||||
|
@ -566,25 +446,21 @@ class MyForm(QtGui.QMainWindow):
|
||||||
elif tab == 'chan':
|
elif tab == 'chan':
|
||||||
treeWidget = self.ui.treeWidgetChans
|
treeWidget = self.ui.treeWidgetChans
|
||||||
|
|
||||||
treeWidget.clear()
|
#treeWidget.clear()
|
||||||
|
|
||||||
# get number of (unread) messages
|
# init dictionary
|
||||||
cntUnreadMsg = {}
|
db = {}
|
||||||
queryreturn = sqlQuery('SELECT toaddress, folder, count(msgid) as cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder')
|
enabled = {}
|
||||||
for row in queryreturn:
|
|
||||||
toaddress, folder, cnt = row
|
for toAddress in shared.config.sections():
|
||||||
cntUnreadMsg[toaddress + folder] = cnt
|
if toAddress == 'bitmessagesettings':
|
||||||
|
|
||||||
configSections = sorted(shared.config.sections(), cmp=address_compare)
|
|
||||||
for addressInKeysFile in configSections:
|
|
||||||
if addressInKeysFile == 'bitmessagesettings':
|
|
||||||
continue
|
continue
|
||||||
isEnabled = shared.config.getboolean(
|
isEnabled = shared.config.getboolean(
|
||||||
addressInKeysFile, 'enabled')
|
toAddress, 'enabled')
|
||||||
isChan = shared.safeConfigGetBoolean(
|
isChan = shared.safeConfigGetBoolean(
|
||||||
addressInKeysFile, 'chan')
|
toAddress, 'chan')
|
||||||
isMaillinglist = shared.safeConfigGetBoolean(
|
isMaillinglist = shared.safeConfigGetBoolean(
|
||||||
addressInKeysFile, 'mailinglist')
|
toAddress, 'mailinglist')
|
||||||
|
|
||||||
if tab == 'messages':
|
if tab == 'messages':
|
||||||
if isChan:
|
if isChan:
|
||||||
|
@ -593,39 +469,65 @@ class MyForm(QtGui.QMainWindow):
|
||||||
if not isChan:
|
if not isChan:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
newItem = QtGui.QTreeWidgetItem(treeWidget)
|
db[toAddress] = {}
|
||||||
newItem.setExpanded(True)
|
|
||||||
newItem.setIcon(0, avatarize(addressInKeysFile))
|
|
||||||
newItem.setText(0, unicode(
|
|
||||||
shared.config.get(addressInKeysFile, 'label'), 'utf-8)')
|
|
||||||
+ ' (' + addressInKeysFile + ')')
|
|
||||||
newItem.setData(0, Qt.UserRole, [str(addressInKeysFile), "inbox"])
|
|
||||||
#set text color
|
|
||||||
if isEnabled:
|
|
||||||
if isMaillinglist:
|
|
||||||
brush = QtGui.QBrush(QtGui.QColor(137, 04, 177))
|
|
||||||
else:
|
|
||||||
brush = QtGui.QBrush(QApplication.palette().text().color())
|
|
||||||
else:
|
|
||||||
brush = QtGui.QBrush(QtGui.QColor(128, 128, 128))
|
|
||||||
newItem.setExpanded(False)
|
|
||||||
brush.setStyle(QtCore.Qt.NoBrush)
|
|
||||||
newItem.setForeground(0, brush)
|
|
||||||
|
|
||||||
for folder in folders:
|
for folder in folders:
|
||||||
newSubItem = QtGui.QTreeWidgetItem(newItem)
|
db[toAddress][folder] = 0
|
||||||
|
|
||||||
|
enabled[toAddress] = isEnabled
|
||||||
|
|
||||||
cnt = cntUnreadMsg.get(addressInKeysFile + folder, False)
|
# get number of (unread) messages
|
||||||
if cnt:
|
queryreturn = sqlQuery('SELECT toaddress, folder, count(msgid) as cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder')
|
||||||
unreadText = " (" + str(cnt) + ")"
|
for row in queryreturn:
|
||||||
font = QtGui.QFont()
|
toaddress, folder, cnt = row
|
||||||
font.setBold(True)
|
if toaddress in db and folder in db[toaddress]:
|
||||||
newSubItem.setFont(0, font)
|
db[toaddress][folder] = cnt
|
||||||
else:
|
|
||||||
unreadText = ""
|
if treeWidget.isSortingEnabled():
|
||||||
|
treeWidget.setSortingEnabled(False)
|
||||||
|
|
||||||
|
widgets = {}
|
||||||
|
for i in range (0, treeWidget.topLevelItemCount()):
|
||||||
|
widget = treeWidget.topLevelItem(i)
|
||||||
|
toAddress = widget.address
|
||||||
|
|
||||||
|
if not toAddress in db:
|
||||||
|
treeWidget.takeTopLevelItem(i)
|
||||||
|
i -= 1
|
||||||
|
continue
|
||||||
|
unread = 0
|
||||||
|
for j in range (0, widget.childCount()):
|
||||||
|
subwidget = widget.child(j)
|
||||||
|
try:
|
||||||
|
subwidget.setUnreadCount(db[toAddress][subwidget.folderName])
|
||||||
|
unread += db[toAddress][subwidget.folderName]
|
||||||
|
db[toAddress].pop(subwidget.folderName, None)
|
||||||
|
except:
|
||||||
|
widget.takeChild(i)
|
||||||
|
j -= 1
|
||||||
|
|
||||||
newSubItem.setText(0, _translate("MainWindow", folder) + unreadText)
|
# add missing folders
|
||||||
newSubItem.setData(0, Qt.UserRole, [str(addressInKeysFile), folder])
|
if len(db[toAddress]) > 0:
|
||||||
|
i = 0
|
||||||
|
for f, c in db[toAddress].iteritems():
|
||||||
|
print "adding %s, %i" % (f, c)
|
||||||
|
subwidget = Ui_FolderWidget(widget, i, toAddress, f, c)
|
||||||
|
i += 1
|
||||||
|
widget.setUnreadCount(unread)
|
||||||
|
db.pop(toAddress, None)
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
for toAddress in db:
|
||||||
|
widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"])
|
||||||
|
j = 0
|
||||||
|
unread = 0
|
||||||
|
for folder in folders:
|
||||||
|
subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder])
|
||||||
|
unread += db[toAddress][folder]
|
||||||
|
j += 1
|
||||||
|
widget.setUnreadCount(unread)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
treeWidget.setSortingEnabled(True)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QtGui.QWidget.__init__(self, parent)
|
QtGui.QWidget.__init__(self, parent)
|
||||||
|
@ -1851,6 +1753,12 @@ class MyForm(QtGui.QMainWindow):
|
||||||
|
|
||||||
def changedInboxUnread(self):
|
def changedInboxUnread(self):
|
||||||
self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount())
|
self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount())
|
||||||
|
if self.ui.tabWidget.currentIndex() == 0:
|
||||||
|
self.rerenderTabTreeMessages()
|
||||||
|
elif self.ui.tabWidget.currentIndex() == 2:
|
||||||
|
self.rerenderTabTreeSubscriptions()
|
||||||
|
elif self.ui.tabWidget.currentIndex() == 3:
|
||||||
|
self.rerenderTabTreeChans()
|
||||||
|
|
||||||
def findInboxUnreadCount(self):
|
def findInboxUnreadCount(self):
|
||||||
queryreturn = sqlQuery('''SELECT count(*) from inbox WHERE folder='inbox' and read=0''')
|
queryreturn = sqlQuery('''SELECT count(*) from inbox WHERE folder='inbox' and read=0''')
|
||||||
|
@ -3613,12 +3521,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f
|
||||||
tableWidget.item(currentRow, 2).setFont(font)
|
tableWidget.item(currentRow, 2).setFont(font)
|
||||||
tableWidget.item(currentRow, 3).setFont(font)
|
tableWidget.item(currentRow, 3).setFont(font)
|
||||||
self.changedInboxUnread()
|
self.changedInboxUnread()
|
||||||
# if self.ui.tabWidget.currentIndex() == 0:
|
|
||||||
# self.rerenderTabTreeMessages()
|
|
||||||
# elif self.ui.tabWidget.currentIndex() == 2:
|
|
||||||
# self.rerenderTabTreeSubscriptions()
|
|
||||||
# elif self.ui.tabWidget.currentIndex() == 3:
|
|
||||||
# self.rerenderTabTreeChans()
|
|
||||||
else:
|
else:
|
||||||
data = self.getCurrentMessageId()
|
data = self.getCurrentMessageId()
|
||||||
if data != False:
|
if data != False:
|
||||||
|
|
133
src/bitmessageqt/foldertree.py
Normal file
133
src/bitmessageqt/foldertree.py
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
|
from utils import *
|
||||||
|
import shared
|
||||||
|
|
||||||
|
class Ui_FolderWidget(QtGui.QTreeWidgetItem):
|
||||||
|
folderWeight = {"inbox": 1, "sent": 2, "trash": 3}
|
||||||
|
def __init__(self, parent, pos = 0, address = "", folderName = "", unreadCount = 0):
|
||||||
|
super(QtGui.QTreeWidgetItem, self).__init__()
|
||||||
|
self.address = address
|
||||||
|
self.folderName = folderName
|
||||||
|
self.unreadCount = unreadCount
|
||||||
|
parent.insertChild(pos, self)
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
def setAddress(self, address):
|
||||||
|
self.address = str(address)
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
def setUnreadCount(self, cnt):
|
||||||
|
self.unreadCount = int(cnt)
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
def setFolderName(self, fname):
|
||||||
|
self.folderName = str(fname)
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
def updateText(self):
|
||||||
|
text = QtGui.QApplication.translate("MainWindow", self.folderName)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
if self.unreadCount > 0:
|
||||||
|
text += " (" + str(self.unreadCount) + ")"
|
||||||
|
font.setBold(True)
|
||||||
|
else:
|
||||||
|
font.setBold(False)
|
||||||
|
self.setFont(0, font)
|
||||||
|
self.setText(0, text)
|
||||||
|
self.setToolTip(0, text)
|
||||||
|
self.setData(0, QtCore.Qt.UserRole, [self.address, self.folderName])
|
||||||
|
|
||||||
|
# inbox, sent, thrash first, rest alphabetically
|
||||||
|
def __lt__(self, other):
|
||||||
|
if (isinstance(other, Ui_FolderWidget)):
|
||||||
|
if self.folderName in self.folderWeight:
|
||||||
|
x = self.folderWeight[self.folderName]
|
||||||
|
else:
|
||||||
|
x = 4
|
||||||
|
if other.folderName in self.folderWeight:
|
||||||
|
y = self.folderWeight[other.folderName]
|
||||||
|
else:
|
||||||
|
y = 4
|
||||||
|
|
||||||
|
if x == y:
|
||||||
|
return self.folderName > other.folderName
|
||||||
|
else:
|
||||||
|
return x > y
|
||||||
|
|
||||||
|
return super(QtGui.QTreeWidgetItem, self).__lt__(other)
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_AddressWidget(QtGui.QTreeWidgetItem):
|
||||||
|
def __init__(self, parent, pos = 0, address = "", unreadCount = 0):
|
||||||
|
super(QtGui.QTreeWidgetItem, self).__init__()
|
||||||
|
self.address = address
|
||||||
|
self.unreadCount = unreadCount
|
||||||
|
parent.insertTopLevelItem(pos, self)
|
||||||
|
# only set default when creating
|
||||||
|
#super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled'))
|
||||||
|
self.setExpanded(shared.safeConfigGetBoolean(self.address, 'enabled'))
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
def setAddress(self, address):
|
||||||
|
self.address = str(address)
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
def setUnreadCount(self, cnt):
|
||||||
|
self.unreadCount = int(cnt)
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
def updateText(self):
|
||||||
|
text = QtGui.QApplication.translate("MainWindow",
|
||||||
|
unicode(shared.config.get(self.address, 'label'), 'utf-8)')
|
||||||
|
+ ' (' + self.address + ')')
|
||||||
|
|
||||||
|
font = QtGui.QFont()
|
||||||
|
if self.unreadCount > 0:
|
||||||
|
# only show message count if the child doesn't show
|
||||||
|
if not self.isExpanded():
|
||||||
|
text += " (" + str(self.unreadCount) + ")"
|
||||||
|
font.setBold(True)
|
||||||
|
else:
|
||||||
|
font.setBold(False)
|
||||||
|
self.setFont(0, font)
|
||||||
|
|
||||||
|
#set text color
|
||||||
|
if shared.safeConfigGetBoolean(self.address, 'enabled'):
|
||||||
|
if shared.safeConfigGetBoolean(self.address, 'mailinglist'):
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(137, 04, 177))
|
||||||
|
else:
|
||||||
|
brush = QtGui.QBrush(QtGui.QApplication.palette().text().color())
|
||||||
|
#self.setExpanded(True)
|
||||||
|
else:
|
||||||
|
brush = QtGui.QBrush(QtGui.QColor(128, 128, 128))
|
||||||
|
#self.setExpanded(False)
|
||||||
|
brush.setStyle(QtCore.Qt.NoBrush)
|
||||||
|
self.setForeground(0, brush)
|
||||||
|
|
||||||
|
self.setIcon(0, avatarize(self.address))
|
||||||
|
self.setText(0, text)
|
||||||
|
self.setToolTip(0, text)
|
||||||
|
self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"])
|
||||||
|
|
||||||
|
def setExpanded(self, expand):
|
||||||
|
super(Ui_AddressWidget, self).setExpanded(expand)
|
||||||
|
self.updateText()
|
||||||
|
|
||||||
|
# label (or address) alphabetically, disabled at the end
|
||||||
|
def __lt__(self, other):
|
||||||
|
if (isinstance(other, Ui_AddressWidget)):
|
||||||
|
if shared.config.getboolean(self.address, 'enabled') == shared.config.getboolean(other.address, 'enabled'):
|
||||||
|
if shared.config.get(self.address, 'label'):
|
||||||
|
x = shared.config.get(self.address, 'label').decode('utf-8').lower()
|
||||||
|
else:
|
||||||
|
x = self.address.decode('utf-8').lower()
|
||||||
|
if shared.config.get(other.address, 'label'):
|
||||||
|
y = shared.config.get(other.address, 'label').decode('utf-8').lower()
|
||||||
|
else:
|
||||||
|
y = other.address.decode('utf-8').lower()
|
||||||
|
return y < x
|
||||||
|
# else:
|
||||||
|
return (False if shared.config.getboolean(self.address, 'enabled') else True)
|
||||||
|
|
||||||
|
return super(QtGui.QTreeWidgetItem, self).__lt__(other)
|
104
src/bitmessageqt/utils.py
Normal file
104
src/bitmessageqt/utils.py
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
from PyQt4 import QtGui
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
import shared
|
||||||
|
from addresses import addBMIfNotPresent
|
||||||
|
|
||||||
|
def identiconize(address):
|
||||||
|
size = 48
|
||||||
|
|
||||||
|
# If you include another identicon library, please generate an
|
||||||
|
# example identicon with the following md5 hash:
|
||||||
|
# 3fd4bf901b9d4ea1394f0fb358725b28
|
||||||
|
|
||||||
|
try:
|
||||||
|
identicon_lib = shared.config.get('bitmessagesettings', 'identiconlib')
|
||||||
|
except:
|
||||||
|
# default to qidenticon_two_x
|
||||||
|
identicon_lib = 'qidenticon_two_x'
|
||||||
|
|
||||||
|
# As an 'identiconsuffix' you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators. (Note however, that E-Mail programs might convert the BM-address to lowercase first.)
|
||||||
|
# It can be used as a pseudo-password to salt the generation of the identicons to decrease the risk
|
||||||
|
# of attacks where someone creates an address to mimic someone else's identicon.
|
||||||
|
identiconsuffix = shared.config.get('bitmessagesettings', 'identiconsuffix')
|
||||||
|
|
||||||
|
if not shared.config.getboolean('bitmessagesettings', 'useidenticons'):
|
||||||
|
idcon = QtGui.QIcon()
|
||||||
|
return idcon
|
||||||
|
|
||||||
|
if (identicon_lib[:len('qidenticon')] == 'qidenticon'):
|
||||||
|
# print identicon_lib
|
||||||
|
# originally by:
|
||||||
|
# :Author:Shin Adachi <shn@glucose.jp>
|
||||||
|
# Licesensed under FreeBSD License.
|
||||||
|
# stripped from PIL and uses QT instead (by sendiulo, same license)
|
||||||
|
import qidenticon
|
||||||
|
hash = hashlib.md5(addBMIfNotPresent(address)+identiconsuffix).hexdigest()
|
||||||
|
use_two_colors = (identicon_lib[:len('qidenticon_two')] == 'qidenticon_two')
|
||||||
|
opacity = int(not((identicon_lib == 'qidenticon_x') | (identicon_lib == 'qidenticon_two_x') | (identicon_lib == 'qidenticon_b') | (identicon_lib == 'qidenticon_two_b')))*255
|
||||||
|
penwidth = 0
|
||||||
|
image = qidenticon.render_identicon(int(hash, 16), size, use_two_colors, opacity, penwidth)
|
||||||
|
# filename = './images/identicons/'+hash+'.png'
|
||||||
|
# image.save(filename)
|
||||||
|
idcon = QtGui.QIcon()
|
||||||
|
idcon.addPixmap(image, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
return idcon
|
||||||
|
elif identicon_lib == 'pydenticon':
|
||||||
|
# print identicon_lib
|
||||||
|
# Here you could load pydenticon.py (just put it in the "src" folder of your Bitmessage source)
|
||||||
|
from pydenticon import Pydenticon
|
||||||
|
# It is not included in the source, because it is licensed under GPLv3
|
||||||
|
# GPLv3 is a copyleft license that would influence our licensing
|
||||||
|
# Find the source here: http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py
|
||||||
|
# note that it requires PIL to be installed: http://www.pythonware.com/products/pil/
|
||||||
|
idcon_render = Pydenticon(addBMIfNotPresent(address)+identiconsuffix, size*3)
|
||||||
|
rendering = idcon_render._render()
|
||||||
|
data = rendering.convert("RGBA").tostring("raw", "RGBA")
|
||||||
|
qim = QImage(data, size, size, QImage.Format_ARGB32)
|
||||||
|
pix = QPixmap.fromImage(qim)
|
||||||
|
idcon = QtGui.QIcon()
|
||||||
|
idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
return idcon
|
||||||
|
|
||||||
|
def avatarize(address):
|
||||||
|
"""
|
||||||
|
loads a supported image for the given address' hash form 'avatars' folder
|
||||||
|
falls back to default avatar if 'default.*' file exists
|
||||||
|
falls back to identiconize(address)
|
||||||
|
"""
|
||||||
|
idcon = QtGui.QIcon()
|
||||||
|
hash = hashlib.md5(addBMIfNotPresent(address)).hexdigest()
|
||||||
|
str_broadcast_subscribers = '[Broadcast subscribers]'
|
||||||
|
if address == str_broadcast_subscribers:
|
||||||
|
# don't hash [Broadcast subscribers]
|
||||||
|
hash = address
|
||||||
|
# http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats
|
||||||
|
# print QImageReader.supportedImageFormats ()
|
||||||
|
# QImageReader.supportedImageFormats ()
|
||||||
|
extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA']
|
||||||
|
# try to find a specific avatar
|
||||||
|
for ext in extensions:
|
||||||
|
lower_hash = shared.appdata + 'avatars/' + hash + '.' + ext.lower()
|
||||||
|
upper_hash = shared.appdata + 'avatars/' + hash + '.' + ext.upper()
|
||||||
|
if os.path.isfile(lower_hash):
|
||||||
|
# print 'found avatar of ', address
|
||||||
|
idcon.addFile(lower_hash)
|
||||||
|
return idcon
|
||||||
|
elif os.path.isfile(upper_hash):
|
||||||
|
# print 'found avatar of ', address
|
||||||
|
idcon.addFile(upper_hash)
|
||||||
|
return idcon
|
||||||
|
# if we haven't found any, try to find a default avatar
|
||||||
|
for ext in extensions:
|
||||||
|
lower_default = shared.appdata + 'avatars/' + 'default.' + ext.lower()
|
||||||
|
upper_default = shared.appdata + 'avatars/' + 'default.' + ext.upper()
|
||||||
|
if os.path.isfile(lower_default):
|
||||||
|
default = lower_default
|
||||||
|
idcon.addFile(lower_default)
|
||||||
|
return idcon
|
||||||
|
elif os.path.isfile(upper_default):
|
||||||
|
default = upper_default
|
||||||
|
idcon.addFile(upper_default)
|
||||||
|
return idcon
|
||||||
|
# If no avatar is found
|
||||||
|
return identiconize(address)
|
Loading…
Reference in New Issue
Block a user