|
|
|
@ -1,63 +1,78 @@
|
|
|
|
|
from debug import logger
|
|
|
|
|
# pylint: disable=too-many-lines,broad-except,too-many-instance-attributes,global-statement,too-few-public-methods
|
|
|
|
|
# pylint: disable=too-many-statements,too-many-branches,attribute-defined-outside-init,too-many-arguments,no-member
|
|
|
|
|
# pylint: disable=unused-argument,no-self-use,too-many-locals,unused-variable,too-many-nested-blocks
|
|
|
|
|
# pylint: disable=too-many-return-statements,protected-access,super-init-not-called,non-parent-init-called
|
|
|
|
|
"""
|
|
|
|
|
Initialise the QT interface
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import hashlib
|
|
|
|
|
import locale
|
|
|
|
|
import os
|
|
|
|
|
import random
|
|
|
|
|
import string
|
|
|
|
|
import sys
|
|
|
|
|
import textwrap
|
|
|
|
|
import time
|
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
|
|
|
|
import debug
|
|
|
|
|
from debug import logger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
from PyQt4 import QtCore, QtGui
|
|
|
|
|
from PyQt4.QtNetwork import QLocalSocket, QLocalServer
|
|
|
|
|
except Exception as err:
|
|
|
|
|
logmsg = '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).'
|
|
|
|
|
except ImportError:
|
|
|
|
|
logmsg = (
|
|
|
|
|
'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).'
|
|
|
|
|
)
|
|
|
|
|
logger.critical(logmsg, exc_info=True)
|
|
|
|
|
sys.exit()
|
|
|
|
|
|
|
|
|
|
from tr import _translate
|
|
|
|
|
from addresses import decodeAddress, addBMIfNotPresent
|
|
|
|
|
import shared
|
|
|
|
|
from bitmessageui import Ui_MainWindow
|
|
|
|
|
from bmconfigparser import BMConfigParser
|
|
|
|
|
|
|
|
|
|
from sqlite3 import register_adapter # pylint: disable=wrong-import-order
|
|
|
|
|
|
|
|
|
|
import defaults
|
|
|
|
|
from namecoin import namecoinConnection
|
|
|
|
|
from messageview import MessageView
|
|
|
|
|
from migrationwizard import Ui_MigrationWizard
|
|
|
|
|
from foldertree import (
|
|
|
|
|
AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget,
|
|
|
|
|
MessageList_AddressWidget, MessageList_SubjectWidget,
|
|
|
|
|
Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress)
|
|
|
|
|
from settings import Ui_settingsDialog
|
|
|
|
|
import settingsmixin
|
|
|
|
|
import support
|
|
|
|
|
import locale
|
|
|
|
|
import time
|
|
|
|
|
import os
|
|
|
|
|
import hashlib
|
|
|
|
|
from pyelliptic.openssl import OpenSSL
|
|
|
|
|
import textwrap
|
|
|
|
|
import debug
|
|
|
|
|
import random
|
|
|
|
|
from sqlite3 import register_adapter
|
|
|
|
|
import string
|
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
from helper_ackPayload import genAckPayload
|
|
|
|
|
from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure
|
|
|
|
|
import helper_search
|
|
|
|
|
import knownnodes
|
|
|
|
|
import l10n
|
|
|
|
|
import openclpow
|
|
|
|
|
from utils import str_broadcast_subscribers, avatarize
|
|
|
|
|
from account import (
|
|
|
|
|
getSortedAccounts, getSortedSubscriptions, accountClass, BMAccount,
|
|
|
|
|
GatewayAccount, MailchuckAccount, AccountColor)
|
|
|
|
|
import dialogs
|
|
|
|
|
from helper_generic import powQueueSize
|
|
|
|
|
from network.stats import pendingDownload, pendingUpload
|
|
|
|
|
from uisignaler import UISignaler
|
|
|
|
|
import knownnodes
|
|
|
|
|
import paths
|
|
|
|
|
from proofofwork import getPowType
|
|
|
|
|
import queues
|
|
|
|
|
import shared
|
|
|
|
|
import shutdown
|
|
|
|
|
import state
|
|
|
|
|
from statusbar import BMStatusBar
|
|
|
|
|
import upnp
|
|
|
|
|
|
|
|
|
|
from bitmessageqt import sound, support, dialogs
|
|
|
|
|
from bitmessageqt.foldertree import (
|
|
|
|
|
AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget, MessageList_AddressWidget,
|
|
|
|
|
MessageList_SubjectWidget, Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress,
|
|
|
|
|
)
|
|
|
|
|
from bitmessageqt.account import (
|
|
|
|
|
getSortedAccounts, getSortedSubscriptions, accountClass, BMAccount, GatewayAccount, MailchuckAccount, AccountColor,
|
|
|
|
|
)
|
|
|
|
|
from bitmessageqt.bitmessageui import Ui_MainWindow, settingsmixin
|
|
|
|
|
from bitmessageqt.messageview import MessageView
|
|
|
|
|
from bitmessageqt.migrationwizard import Ui_MigrationWizard
|
|
|
|
|
from bitmessageqt.settings import Ui_settingsDialog
|
|
|
|
|
from bitmessageqt.utils import str_broadcast_subscribers, avatarize
|
|
|
|
|
from bitmessageqt.uisignaler import UISignaler
|
|
|
|
|
from bitmessageqt.statusbar import BMStatusBar
|
|
|
|
|
|
|
|
|
|
from addresses import decodeAddress, addBMIfNotPresent
|
|
|
|
|
from bmconfigparser import BMConfigParser
|
|
|
|
|
from namecoin import namecoinConnection
|
|
|
|
|
from helper_ackPayload import genAckPayload
|
|
|
|
|
from helper_generic import powQueueSize
|
|
|
|
|
from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure
|
|
|
|
|
from network.stats import pendingDownload, pendingUpload
|
|
|
|
|
from network.asyncore_pollchoose import set_rates
|
|
|
|
|
import sound
|
|
|
|
|
from proofofwork import getPowType
|
|
|
|
|
from tr import _translate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
@ -66,8 +81,15 @@ except ImportError:
|
|
|
|
|
get_plugins = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qmytranslator = None
|
|
|
|
|
qsystranslator = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def change_translation(newlocale):
|
|
|
|
|
"""Change a translation to a new locale"""
|
|
|
|
|
|
|
|
|
|
global qmytranslator, qsystranslator
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if not qmytranslator.isEmpty():
|
|
|
|
|
QtGui.QApplication.removeTranslator(qmytranslator)
|
|
|
|
@ -80,15 +102,16 @@ def change_translation(newlocale):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
qmytranslator = QtCore.QTranslator()
|
|
|
|
|
translationpath = os.path.join (paths.codePath(), 'translations', 'bitmessage_' + newlocale)
|
|
|
|
|
translationpath = os.path.join(paths.codePath(), 'translations', 'bitmessage_' + newlocale)
|
|
|
|
|
qmytranslator.load(translationpath)
|
|
|
|
|
QtGui.QApplication.installTranslator(qmytranslator)
|
|
|
|
|
|
|
|
|
|
qsystranslator = QtCore.QTranslator()
|
|
|
|
|
if paths.frozen:
|
|
|
|
|
translationpath = os.path.join (paths.codePath(), 'translations', 'qt_' + newlocale)
|
|
|
|
|
translationpath = os.path.join(paths.codePath(), 'translations', 'qt_' + newlocale)
|
|
|
|
|
else:
|
|
|
|
|
translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
|
|
|
|
|
translationpath = os.path.join(str(QtCore.QLibraryInfo.location(
|
|
|
|
|
QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale)
|
|
|
|
|
qsystranslator.load(translationpath)
|
|
|
|
|
QtGui.QApplication.installTranslator(qsystranslator)
|
|
|
|
|
|
|
|
|
@ -109,7 +132,8 @@ def change_translation(newlocale):
|
|
|
|
|
logger.error("Failed to set locale to %s", lang, exc_info=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
class MyForm(settingsmixin.SMainWindow): # pylint: disable=too-many-public-methods
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
# the last time that a message arrival sound was played
|
|
|
|
|
lastSoundTime = datetime.now() - timedelta(days=1)
|
|
|
|
@ -121,6 +145,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
REPLY_TYPE_CHAN = 1
|
|
|
|
|
|
|
|
|
|
def init_file_menu(self):
|
|
|
|
|
"""Initialise the file menu"""
|
|
|
|
|
|
|
|
|
|
QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL(
|
|
|
|
|
"triggered()"), self.quit)
|
|
|
|
|
QtCore.QObject.connect(self.ui.actionNetworkSwitch, QtCore.SIGNAL(
|
|
|
|
@ -135,9 +161,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
QtCore.SIGNAL(
|
|
|
|
|
"triggered()"),
|
|
|
|
|
self.click_actionRegenerateDeterministicAddresses)
|
|
|
|
|
QtCore.QObject.connect(self.ui.pushButtonAddChan, QtCore.SIGNAL(
|
|
|
|
|
"clicked()"),
|
|
|
|
|
self.click_actionJoinChan) # also used for creating chans.
|
|
|
|
|
QtCore.QObject.connect(
|
|
|
|
|
self.ui.pushButtonAddChan,
|
|
|
|
|
QtCore.SIGNAL("clicked()"),
|
|
|
|
|
self.click_actionJoinChan) # also used for creating chans.
|
|
|
|
|
QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL(
|
|
|
|
|
"clicked()"), self.click_NewAddressDialog)
|
|
|
|
|
QtCore.QObject.connect(self.ui.pushButtonAddAddressBook, QtCore.SIGNAL(
|
|
|
|
@ -162,7 +189,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
"triggered()"), self.click_actionHelp)
|
|
|
|
|
|
|
|
|
|
def init_inbox_popup_menu(self, connectSignal=True):
|
|
|
|
|
# Popup menu for the Inbox tab
|
|
|
|
|
"""Popup menu for the Inbox tab"""
|
|
|
|
|
|
|
|
|
|
self.ui.inboxContextMenuToolbar = QtGui.QToolBar()
|
|
|
|
|
# Actions
|
|
|
|
|
self.actionReply = self.ui.inboxContextMenuToolbar.addAction(_translate(
|
|
|
|
@ -199,24 +227,28 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.ui.tableWidgetInbox.setContextMenuPolicy(
|
|
|
|
|
QtCore.Qt.CustomContextMenu)
|
|
|
|
|
if connectSignal:
|
|
|
|
|
self.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL(
|
|
|
|
|
'customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuInbox)
|
|
|
|
|
self.connect(
|
|
|
|
|
self.ui.tableWidgetInbox,
|
|
|
|
|
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuInbox)
|
|
|
|
|
self.ui.tableWidgetInboxSubscriptions.setContextMenuPolicy(
|
|
|
|
|
QtCore.Qt.CustomContextMenu)
|
|
|
|
|
if connectSignal:
|
|
|
|
|
self.connect(self.ui.tableWidgetInboxSubscriptions, QtCore.SIGNAL(
|
|
|
|
|
'customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuInbox)
|
|
|
|
|
self.connect(
|
|
|
|
|
self.ui.tableWidgetInboxSubscriptions,
|
|
|
|
|
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuInbox)
|
|
|
|
|
self.ui.tableWidgetInboxChans.setContextMenuPolicy(
|
|
|
|
|
QtCore.Qt.CustomContextMenu)
|
|
|
|
|
if connectSignal:
|
|
|
|
|
self.connect(self.ui.tableWidgetInboxChans, QtCore.SIGNAL(
|
|
|
|
|
'customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuInbox)
|
|
|
|
|
self.connect(
|
|
|
|
|
self.ui.tableWidgetInboxChans,
|
|
|
|
|
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuInbox)
|
|
|
|
|
|
|
|
|
|
def init_identities_popup_menu(self, connectSignal=True):
|
|
|
|
|
# Popup menu for the Your Identities tab
|
|
|
|
|
"""Popup menu for the Your Identities tab"""
|
|
|
|
|
|
|
|
|
|
self.ui.addressContextMenuToolbarYourIdentities = QtGui.QToolBar()
|
|
|
|
|
# Actions
|
|
|
|
|
self.actionNewYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction(_translate(
|
|
|
|
@ -251,9 +283,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.ui.treeWidgetYourIdentities.setContextMenuPolicy(
|
|
|
|
|
QtCore.Qt.CustomContextMenu)
|
|
|
|
|
if connectSignal:
|
|
|
|
|
self.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL(
|
|
|
|
|
'customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuYourIdentities)
|
|
|
|
|
self.connect(
|
|
|
|
|
self.ui.treeWidgetYourIdentities,
|
|
|
|
|
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuYourIdentities)
|
|
|
|
|
|
|
|
|
|
# load all gui.menu plugins with prefix 'address'
|
|
|
|
|
self.menu_plugins = {'address': []}
|
|
|
|
@ -268,7 +301,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
def init_chan_popup_menu(self, connectSignal=True):
|
|
|
|
|
# Popup menu for the Channels tab
|
|
|
|
|
"""Popup menu for the Channels tab"""
|
|
|
|
|
|
|
|
|
|
self.ui.addressContextMenuToolbar = QtGui.QToolBar()
|
|
|
|
|
# Actions
|
|
|
|
|
self.actionNew = self.ui.addressContextMenuToolbar.addAction(_translate(
|
|
|
|
@ -298,12 +332,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.ui.treeWidgetChans.setContextMenuPolicy(
|
|
|
|
|
QtCore.Qt.CustomContextMenu)
|
|
|
|
|
if connectSignal:
|
|
|
|
|
self.connect(self.ui.treeWidgetChans, QtCore.SIGNAL(
|
|
|
|
|
'customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuChan)
|
|
|
|
|
self.connect(
|
|
|
|
|
self.ui.treeWidgetChans,
|
|
|
|
|
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuChan)
|
|
|
|
|
|
|
|
|
|
def init_addressbook_popup_menu(self, connectSignal=True):
|
|
|
|
|
# Popup menu for the Address Book page
|
|
|
|
|
"""Popup menu for the Address Book page"""
|
|
|
|
|
|
|
|
|
|
self.ui.addressBookContextMenuToolbar = QtGui.QToolBar()
|
|
|
|
|
# Actions
|
|
|
|
|
self.actionAddressBookSend = self.ui.addressBookContextMenuToolbar.addAction(
|
|
|
|
@ -335,12 +371,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.ui.tableWidgetAddressBook.setContextMenuPolicy(
|
|
|
|
|
QtCore.Qt.CustomContextMenu)
|
|
|
|
|
if connectSignal:
|
|
|
|
|
self.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL(
|
|
|
|
|
'customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuAddressBook)
|
|
|
|
|
self.connect(
|
|
|
|
|
self.ui.tableWidgetAddressBook,
|
|
|
|
|
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuAddressBook)
|
|
|
|
|
|
|
|
|
|
def init_subscriptions_popup_menu(self, connectSignal=True):
|
|
|
|
|
# Popup menu for the Subscriptions page
|
|
|
|
|
"""Popup menu for the Subscriptions page"""
|
|
|
|
|
|
|
|
|
|
self.ui.subscriptionsContextMenuToolbar = QtGui.QToolBar()
|
|
|
|
|
# Actions
|
|
|
|
|
self.actionsubscriptionsNew = self.ui.subscriptionsContextMenuToolbar.addAction(
|
|
|
|
@ -363,12 +401,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.ui.treeWidgetSubscriptions.setContextMenuPolicy(
|
|
|
|
|
QtCore.Qt.CustomContextMenu)
|
|
|
|
|
if connectSignal:
|
|
|
|
|
self.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL(
|
|
|
|
|
'customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuSubscriptions)
|
|
|
|
|
self.connect(
|
|
|
|
|
self.ui.treeWidgetSubscriptions,
|
|
|
|
|
QtCore.SIGNAL('customContextMenuRequested(const QPoint&)'),
|
|
|
|
|
self.on_context_menuSubscriptions)
|
|
|
|
|
|
|
|
|
|
def init_sent_popup_menu(self, connectSignal=True):
|
|
|
|
|
# Popup menu for the Sent page
|
|
|
|
|
"""Popup menu for the Sent page"""
|
|
|
|
|
|
|
|
|
|
self.ui.sentContextMenuToolbar = QtGui.QToolBar()
|
|
|
|
|
# Actions
|
|
|
|
|
self.actionTrashSentMessage = self.ui.sentContextMenuToolbar.addAction(
|
|
|
|
@ -381,11 +421,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.actionForceSend = self.ui.sentContextMenuToolbar.addAction(
|
|
|
|
|
_translate(
|
|
|
|
|
"MainWindow", "Force send"), self.on_action_ForceSend)
|
|
|
|
|
# self.popMenuSent = QtGui.QMenu( self )
|
|
|
|
|
# self.popMenuSent.addAction( self.actionSentClipboard )
|
|
|
|
|
# self.popMenuSent.addAction( self.actionTrashSentMessage )
|
|
|
|
|
|
|
|
|
|
def rerenderTabTreeSubscriptions(self):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
treeWidget = self.ui.treeWidgetSubscriptions
|
|
|
|
|
folders = Ui_FolderWidget.folderWeight.keys()
|
|
|
|
|
folders.remove("new")
|
|
|
|
@ -395,17 +434,16 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
treeWidget.header().setSortIndicator(
|
|
|
|
|
0, QtCore.Qt.AscendingOrder)
|
|
|
|
|
# init dictionary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
db = getSortedSubscriptions(True)
|
|
|
|
|
for address in db:
|
|
|
|
|
for folder in folders:
|
|
|
|
|
if not folder in db[address]:
|
|
|
|
|
if folder not in db[address]:
|
|
|
|
|
db[address][folder] = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if treeWidget.isSortingEnabled():
|
|
|
|
|
treeWidget.setSortingEnabled(False)
|
|
|
|
|
|
|
|
|
|
widgets = {}
|
|
|
|
|
i = 0
|
|
|
|
|
while i < treeWidget.topLevelItemCount():
|
|
|
|
|
widget = treeWidget.topLevelItem(i)
|
|
|
|
@ -413,8 +451,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
toAddress = widget.address
|
|
|
|
|
else:
|
|
|
|
|
toAddress = None
|
|
|
|
|
|
|
|
|
|
if not toAddress in db:
|
|
|
|
|
|
|
|
|
|
if toAddress not in db:
|
|
|
|
|
treeWidget.takeTopLevelItem(i)
|
|
|
|
|
# no increment
|
|
|
|
|
continue
|
|
|
|
@ -433,7 +471,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
j += 1
|
|
|
|
|
|
|
|
|
|
# add missing folders
|
|
|
|
|
if len(db[toAddress]) > 0:
|
|
|
|
|
if db[toAddress]:
|
|
|
|
|
j = 0
|
|
|
|
|
for f, c in db[toAddress].iteritems():
|
|
|
|
|
try:
|
|
|
|
@ -444,10 +482,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
widget.setUnreadCount(unread)
|
|
|
|
|
db.pop(toAddress, None)
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = 0
|
|
|
|
|
for toAddress in db:
|
|
|
|
|
widget = Ui_SubscriptionWidget(treeWidget, i, toAddress, db[toAddress]["inbox"]['count'], db[toAddress]["inbox"]['label'], db[toAddress]["inbox"]['enabled'])
|
|
|
|
|
widget = Ui_SubscriptionWidget(
|
|
|
|
|
treeWidget, i, toAddress,
|
|
|
|
|
db[toAddress]["inbox"]['count'],
|
|
|
|
|
db[toAddress]["inbox"]['label'],
|
|
|
|
|
db[toAddress]["inbox"]['enabled'])
|
|
|
|
|
j = 0
|
|
|
|
|
unread = 0
|
|
|
|
|
for folder in folders:
|
|
|
|
@ -459,23 +501,28 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
j += 1
|
|
|
|
|
widget.setUnreadCount(unread)
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
treeWidget.setSortingEnabled(True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rerenderTabTreeMessages(self):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
self.rerenderTabTree('messages')
|
|
|
|
|
|
|
|
|
|
def rerenderTabTreeChans(self):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
self.rerenderTabTree('chan')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rerenderTabTree(self, tab):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
if tab == 'messages':
|
|
|
|
|
treeWidget = self.ui.treeWidgetYourIdentities
|
|
|
|
|
elif tab == 'chan':
|
|
|
|
|
treeWidget = self.ui.treeWidgetChans
|
|
|
|
|
folders = Ui_FolderWidget.folderWeight.keys()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# sort ascending when creating
|
|
|
|
|
if treeWidget.topLevelItemCount() == 0:
|
|
|
|
|
treeWidget.header().setSortIndicator(
|
|
|
|
@ -483,14 +530,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
# init dictionary
|
|
|
|
|
db = {}
|
|
|
|
|
enabled = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for toAddress in getSortedAccounts():
|
|
|
|
|
isEnabled = BMConfigParser().getboolean(
|
|
|
|
|
toAddress, 'enabled')
|
|
|
|
|
isChan = BMConfigParser().safeGetBoolean(
|
|
|
|
|
toAddress, 'chan')
|
|
|
|
|
isMaillinglist = BMConfigParser().safeGetBoolean(
|
|
|
|
|
toAddress, 'mailinglist')
|
|
|
|
|
|
|
|
|
|
if treeWidget == self.ui.treeWidgetYourIdentities:
|
|
|
|
|
if isChan:
|
|
|
|
@ -502,12 +547,13 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
db[toAddress] = {}
|
|
|
|
|
for folder in folders:
|
|
|
|
|
db[toAddress][folder] = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enabled[toAddress] = isEnabled
|
|
|
|
|
|
|
|
|
|
# get number of (unread) messages
|
|
|
|
|
total = 0
|
|
|
|
|
queryreturn = sqlQuery('SELECT toaddress, folder, count(msgid) as cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder')
|
|
|
|
|
queryreturn = sqlQuery(
|
|
|
|
|
'SELECT toaddress, folder, count(msgid) as cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder')
|
|
|
|
|
for row in queryreturn:
|
|
|
|
|
toaddress, folder, cnt = row
|
|
|
|
|
total += cnt
|
|
|
|
@ -520,11 +566,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
db[None]["sent"] = 0
|
|
|
|
|
db[None]["trash"] = 0
|
|
|
|
|
enabled[None] = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if treeWidget.isSortingEnabled():
|
|
|
|
|
treeWidget.setSortingEnabled(False)
|
|
|
|
|
|
|
|
|
|
widgets = {}
|
|
|
|
|
|
|
|
|
|
i = 0
|
|
|
|
|
while i < treeWidget.topLevelItemCount():
|
|
|
|
|
widget = treeWidget.topLevelItem(i)
|
|
|
|
@ -532,8 +577,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
toAddress = widget.address
|
|
|
|
|
else:
|
|
|
|
|
toAddress = None
|
|
|
|
|
|
|
|
|
|
if not toAddress in db:
|
|
|
|
|
|
|
|
|
|
if toAddress not in db:
|
|
|
|
|
treeWidget.takeTopLevelItem(i)
|
|
|
|
|
# no increment
|
|
|
|
|
continue
|
|
|
|
@ -553,7 +598,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
j += 1
|
|
|
|
|
|
|
|
|
|
# add missing folders
|
|
|
|
|
if len(db[toAddress]) > 0:
|
|
|
|
|
if db[toAddress]:
|
|
|
|
|
j = 0
|
|
|
|
|
for f, c in db[toAddress].iteritems():
|
|
|
|
|
if toAddress is not None and tab == 'messages' and folder == "new":
|
|
|
|
@ -565,7 +610,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
widget.setUnreadCount(unread)
|
|
|
|
|
db.pop(toAddress, None)
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
i = 0
|
|
|
|
|
for toAddress in db:
|
|
|
|
|
widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"], enabled[toAddress])
|
|
|
|
@ -580,10 +625,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
j += 1
|
|
|
|
|
widget.setUnreadCount(unread)
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
treeWidget.setSortingEnabled(True)
|
|
|
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
QtGui.QWidget.__init__(self, parent)
|
|
|
|
|
self.ui = Ui_MainWindow()
|
|
|
|
|
self.ui.setupUi(self)
|
|
|
|
@ -591,12 +638,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
# Ask the user if we may delete their old version 1 addresses if they
|
|
|
|
|
# have any.
|
|
|
|
|
for addressInKeysFile in getSortedAccounts():
|
|
|
|
|
status, addressVersionNumber, streamNumber, hash = decodeAddress(
|
|
|
|
|
status, addressVersionNumber, streamNumber, addressHash = decodeAddress(
|
|
|
|
|
addressInKeysFile)
|
|
|
|
|
if addressVersionNumber == 1:
|
|
|
|
|
displayMsg = _translate(
|
|
|
|
|
"MainWindow", "One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. "
|
|
|
|
|
+ "May we delete it now?").arg(addressInKeysFile)
|
|
|
|
|
"MainWindow",
|
|
|
|
|
'One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer '
|
|
|
|
|
'supported. May we delete it now?'
|
|
|
|
|
).arg(addressInKeysFile)
|
|
|
|
|
reply = QtGui.QMessageBox.question(
|
|
|
|
|
self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
|
|
|
|
if reply == QtGui.QMessageBox.Yes:
|
|
|
|
@ -606,11 +655,13 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
# Configure Bitmessage to start on startup (or remove the
|
|
|
|
|
# configuration) based on the setting in the keys.dat file
|
|
|
|
|
if 'win32' in sys.platform or 'win64' in sys.platform:
|
|
|
|
|
|
|
|
|
|
# Auto-startup for Windows
|
|
|
|
|
RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
|
|
|
|
|
self.settings = QtCore.QSettings(RUN_PATH, QtCore.QSettings.NativeFormat)
|
|
|
|
|
self.settings.remove(
|
|
|
|
|
"PyBitmessage") # In case the user moves the program and the registry entry is no longer valid, this will delete the old registry entry.
|
|
|
|
|
# In case the user moves the program and the registry entry is no longer
|
|
|
|
|
# valid, this will delete the old registry entry.
|
|
|
|
|
self.settings.remove("PyBitmessage")
|
|
|
|
|
if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'):
|
|
|
|
|
self.settings.setValue("PyBitmessage", sys.argv[0])
|
|
|
|
|
elif 'darwin' in sys.platform:
|
|
|
|
@ -622,13 +673,13 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
|
|
|
|
|
# e.g. for editing labels
|
|
|
|
|
self.recurDepth = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# switch back to this when replying
|
|
|
|
|
self.replyFromTab = None
|
|
|
|
|
|
|
|
|
|
# so that quit won't loop
|
|
|
|
|
self.quitAccepted = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.init_file_menu()
|
|
|
|
|
self.init_inbox_popup_menu()
|
|
|
|
|
self.init_identities_popup_menu()
|
|
|
|
@ -724,13 +775,13 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.unreadCount = 0
|
|
|
|
|
|
|
|
|
|
# Set the icon sizes for the identicons
|
|
|
|
|
identicon_size = 3*7
|
|
|
|
|
identicon_size = 3 * 7
|
|
|
|
|
self.ui.tableWidgetInbox.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
|
|
|
|
self.ui.treeWidgetChans.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
|
|
|
|
self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
|
|
|
|
self.ui.treeWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
|
|
|
|
self.ui.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.UISignalThread = UISignaler.get()
|
|
|
|
|
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
|
"writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable)
|
|
|
|
@ -740,10 +791,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
"updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByToAddress)
|
|
|
|
|
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
|
"updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), self.updateSentItemStatusByAckdata)
|
|
|
|
|
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
|
"displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayNewInboxMessage)
|
|
|
|
|
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
|
"displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayNewSentMessage)
|
|
|
|
|
QtCore.QObject.connect(
|
|
|
|
|
self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
|
"displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"),
|
|
|
|
|
self.displayNewInboxMessage)
|
|
|
|
|
QtCore.QObject.connect(
|
|
|
|
|
self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
|
("displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,"
|
|
|
|
|
"PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)")),
|
|
|
|
|
self.displayNewSentMessage)
|
|
|
|
|
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
|
"setStatusIcon(PyQt_PyObject)"), self.setStatusIcon)
|
|
|
|
|
QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL(
|
|
|
|
@ -784,16 +840,16 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
|
|
|
|
|
self.rerenderComboBoxSendFrom()
|
|
|
|
|
self.rerenderComboBoxSendFromBroadcast()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Put the TTL slider in the correct spot
|
|
|
|
|
TTL = BMConfigParser().getint('bitmessagesettings', 'ttl')
|
|
|
|
|
if TTL < 3600: # an hour
|
|
|
|
|
if TTL < 3600: # an hour
|
|
|
|
|
TTL = 3600
|
|
|
|
|
elif TTL > 28*24*60*60: # 28 days
|
|
|
|
|
TTL = 28*24*60*60
|
|
|
|
|
self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1/3.199))
|
|
|
|
|
elif TTL > 28 * 24 * 60 * 60: # 28 days
|
|
|
|
|
TTL = 28 * 24 * 60 * 60
|
|
|
|
|
self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1 / 3.199))
|
|
|
|
|
self.updateHumanFriendlyTTLDescription(TTL)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL(
|
|
|
|
|
"valueChanged(int)"), self.updateTTL)
|
|
|
|
|
|
|
|
|
@ -805,20 +861,24 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
# Hide the 'Fetch Namecoin ID' button if we can't.
|
|
|
|
|
if BMConfigParser().safeGetBoolean(
|
|
|
|
|
'bitmessagesettings', 'dontconnect'
|
|
|
|
|
) or self.namecoin.test()[0] == 'failed':
|
|
|
|
|
) or self.namecoin.test()[0] == 'failed':
|
|
|
|
|
logger.warning(
|
|
|
|
|
'There was a problem testing for a Namecoin daemon. Hiding the'
|
|
|
|
|
' Fetch Namecoin ID button')
|
|
|
|
|
self.ui.pushButtonFetchNamecoinID.hide()
|
|
|
|
|
|
|
|
|
|
def updateTTL(self, sliderPosition):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
TTL = int(sliderPosition ** 3.199 + 3600)
|
|
|
|
|
self.updateHumanFriendlyTTLDescription(TTL)
|
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL))
|
|
|
|
|
BMConfigParser().save()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def updateHumanFriendlyTTLDescription(self, TTL):
|
|
|
|
|
numberOfHours = int(round(TTL / (60*60)))
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
numberOfHours = int(round(TTL / (60 * 60)))
|
|
|
|
|
font = QtGui.QFont()
|
|
|
|
|
stylesheet = ""
|
|
|
|
|
|
|
|
|
@ -827,19 +887,28 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, numberOfHours) +
|
|
|
|
|
", " +
|
|
|
|
|
_translate("MainWindow", "not recommended for chans", None, QtCore.QCoreApplication.CodecForTr)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
stylesheet = "QLabel { color : red; }"
|
|
|
|
|
font.setBold(True)
|
|
|
|
|
else:
|
|
|
|
|
numberOfDays = int(round(TTL / (24*60*60)))
|
|
|
|
|
self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n day(s)", None, QtCore.QCoreApplication.CodecForTr, numberOfDays))
|
|
|
|
|
numberOfDays = int(round(TTL / (24 * 60 * 60)))
|
|
|
|
|
self.ui.labelHumanFriendlyTTLDescription.setText(
|
|
|
|
|
_translate(
|
|
|
|
|
"MainWindow",
|
|
|
|
|
"%n day(s)",
|
|
|
|
|
None,
|
|
|
|
|
QtCore.QCoreApplication.CodecForTr,
|
|
|
|
|
numberOfDays))
|
|
|
|
|
font.setBold(False)
|
|
|
|
|
self.ui.labelHumanFriendlyTTLDescription.setStyleSheet(stylesheet)
|
|
|
|
|
self.ui.labelHumanFriendlyTTLDescription.setFont(font)
|
|
|
|
|
|
|
|
|
|
# Show or hide the application window after clicking an item within the
|
|
|
|
|
# tray icon or, on Windows, the try icon itself.
|
|
|
|
|
def appIndicatorShowOrHideWindow(self):
|
|
|
|
|
"""
|
|
|
|
|
Show or hide the application window after clicking an item within the tray icon or, on Windows,
|
|
|
|
|
the try icon itself.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
if not self.actionShow.isChecked():
|
|
|
|
|
self.hide()
|
|
|
|
|
else:
|
|
|
|
@ -849,16 +918,18 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.raise_()
|
|
|
|
|
self.activateWindow()
|
|
|
|
|
|
|
|
|
|
# show the application window
|
|
|
|
|
def appIndicatorShow(self):
|
|
|
|
|
"""show the application window"""
|
|
|
|
|
|
|
|
|
|
if self.actionShow is None:
|
|
|
|
|
return
|
|
|
|
|
if not self.actionShow.isChecked():
|
|
|
|
|
self.actionShow.setChecked(True)
|
|
|
|
|
self.appIndicatorShowOrHideWindow()
|
|
|
|
|
|
|
|
|
|
# unchecks the show item on the application indicator
|
|
|
|
|
def appIndicatorHide(self):
|
|
|
|
|
"""unchecks the show item on the application indicator"""
|
|
|
|
|
|
|
|
|
|
if self.actionShow is None:
|
|
|
|
|
return
|
|
|
|
|
if self.actionShow.isChecked():
|
|
|
|
@ -866,25 +937,16 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.appIndicatorShowOrHideWindow()
|
|
|
|
|
|
|
|
|
|
def appIndicatorSwitchQuietMode(self):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
BMConfigParser().set(
|
|
|
|
|
'bitmessagesettings', 'showtraynotifications',
|
|
|
|
|
str(not self.actionQuiet.isChecked())
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# application indicator show or hide
|
|
|
|
|
"""# application indicator show or hide
|
|
|
|
|
def appIndicatorShowBitmessage(self):
|
|
|
|
|
#if self.actionShow == None:
|
|
|
|
|
# return
|
|
|
|
|
print self.actionShow.isChecked()
|
|
|
|
|
if not self.actionShow.isChecked():
|
|
|
|
|
self.hide()
|
|
|
|
|
#self.setWindowState(self.windowState() & QtCore.Qt.WindowMinimized)
|
|
|
|
|
else:
|
|
|
|
|
self.appIndicatorShowOrHideWindow()"""
|
|
|
|
|
|
|
|
|
|
# Show the program window and select inbox tab
|
|
|
|
|
def appIndicatorInbox(self, item=None):
|
|
|
|
|
"""Show the program window and select inbox tab"""
|
|
|
|
|
|
|
|
|
|
self.appIndicatorShow()
|
|
|
|
|
# select inbox
|
|
|
|
|
self.ui.tabWidget.setCurrentIndex(
|
|
|
|
@ -900,22 +962,24 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
else:
|
|
|
|
|
self.ui.tableWidgetInbox.setCurrentCell(0, 0)
|
|
|
|
|
|
|
|
|
|
# Show the program window and select send tab
|
|
|
|
|
def appIndicatorSend(self):
|
|
|
|
|
"""Show the program window and select send tab"""
|
|
|
|
|
self.appIndicatorShow()
|
|
|
|
|
self.ui.tabWidget.setCurrentIndex(
|
|
|
|
|
self.ui.tabWidget.indexOf(self.ui.send)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Show the program window and select subscriptions tab
|
|
|
|
|
def appIndicatorSubscribe(self):
|
|
|
|
|
"""Show the program window and select subscriptions tab"""
|
|
|
|
|
|
|
|
|
|
self.appIndicatorShow()
|
|
|
|
|
self.ui.tabWidget.setCurrentIndex(
|
|
|
|
|
self.ui.tabWidget.indexOf(self.ui.subscriptions)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Show the program window and select channels tab
|
|
|
|
|
def appIndicatorChannel(self):
|
|
|
|
|
"""Show the program window and select channels tab"""
|
|
|
|
|
|
|
|
|
|
self.appIndicatorShow()
|
|
|
|
|
self.ui.tabWidget.setCurrentIndex(
|
|
|
|
|
self.ui.tabWidget.indexOf(self.ui.chans)
|
|
|
|
@ -961,9 +1025,12 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
for col in (0, 1, 2):
|
|
|
|
|
related.item(rrow, col).setUnread(not status)
|
|
|
|
|
|
|
|
|
|
def propagateUnreadCount(self, address = None, folder = "inbox", widget = None, type = 1):
|
|
|
|
|
def propagateUnreadCount(self, address=None, folder="inbox", widget=None, type_arg=1):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans]
|
|
|
|
|
queryReturn = sqlQuery("SELECT toaddress, folder, COUNT(msgid) AS cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder")
|
|
|
|
|
queryReturn = sqlQuery(
|
|
|
|
|
"SELECT toaddress, folder, COUNT(msgid) AS cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder")
|
|
|
|
|
totalUnread = {}
|
|
|
|
|
normalUnread = {}
|
|
|
|
|
for row in queryReturn:
|
|
|
|
@ -975,12 +1042,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
totalUnread[row[1]] += row[2]
|
|
|
|
|
else:
|
|
|
|
|
totalUnread[row[1]] = row[2]
|
|
|
|
|
queryReturn = sqlQuery("SELECT fromaddress, folder, COUNT(msgid) AS cnt FROM inbox WHERE read = 0 AND toaddress = ? GROUP BY fromaddress, folder", str_broadcast_subscribers)
|
|
|
|
|
queryReturn = sqlQuery(
|
|
|
|
|
"SELECT fromaddress, folder, COUNT(msgid) AS cnt FROM inbox "
|
|
|
|
|
"WHERE read = 0 AND toaddress = ? GROUP BY fromaddress, folder",
|
|
|
|
|
str_broadcast_subscribers)
|
|
|
|
|
broadcastsUnread = {}
|
|
|
|
|
for row in queryReturn:
|
|
|
|
|
broadcastsUnread[row[0]] = {}
|
|
|
|
|
broadcastsUnread[row[0]][row[1]] = row[2]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for treeWidget in widgets:
|
|
|
|
|
root = treeWidget.invisibleRootItem()
|
|
|
|
|
for i in range(root.childCount()):
|
|
|
|
@ -1007,7 +1077,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
if addressItem.type == AccountMixin.ALL and folderName in totalUnread:
|
|
|
|
|
newCount = totalUnread[folderName]
|
|
|
|
|
elif addressItem.type == AccountMixin.SUBSCRIPTION:
|
|
|
|
|
if addressItem.address in broadcastsUnread and folderName in broadcastsUnread[addressItem.address]:
|
|
|
|
|
if addressItem.address in broadcastsUnread and folderName in broadcastsUnread[
|
|
|
|
|
addressItem.address]:
|
|
|
|
|
newCount = broadcastsUnread[addressItem.address][folderName]
|
|
|
|
|
elif addressItem.address in normalUnread and folderName in normalUnread[addressItem.address]:
|
|
|
|
|
newCount = normalUnread[addressItem.address][folderName]
|
|
|
|
@ -1015,16 +1086,20 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
folderItem.setUnreadCount(newCount)
|
|
|
|
|
|
|
|
|
|
def addMessageListItem(self, tableWidget, items):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
sortingEnabled = tableWidget.isSortingEnabled()
|
|
|
|
|
if sortingEnabled:
|
|
|
|
|
tableWidget.setSortingEnabled(False)
|
|
|
|
|
tableWidget.insertRow(0)
|
|
|
|
|
for i in range(len(items)):
|
|
|
|
|
for i, _ in enumerate(items):
|
|
|
|
|
tableWidget.setItem(0, i, items[i])
|
|
|
|
|
if sortingEnabled:
|
|
|
|
|
tableWidget.setSortingEnabled(True)
|
|
|
|
|
|
|
|
|
|
def addMessageListItemSent(self, tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
acct = accountClass(fromAddress)
|
|
|
|
|
if acct is None:
|
|
|
|
|
acct = BMAccount(fromAddress)
|
|
|
|
@ -1063,14 +1138,19 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
statusText = _translate(
|
|
|
|
|
"MainWindow", "Doing work necessary to send broadcast.")
|
|
|
|
|
elif status == 'broadcastsent':
|
|
|
|
|
statusText = _translate("MainWindow", "Broadcast on %1").arg(
|
|
|
|
|
l10n.formatTimestamp(lastactiontime))
|
|
|
|
|
statusText = _translate(
|
|
|
|
|
"MainWindow", "Broadcast on %1").arg(
|
|
|
|
|
l10n.formatTimestamp(lastactiontime))
|
|
|
|
|
elif status == 'toodifficult':
|
|
|
|
|
statusText = _translate("MainWindow", "Problem: The work demanded by the recipient is more difficult than you are willing to do. %1").arg(
|
|
|
|
|
l10n.formatTimestamp(lastactiontime))
|
|
|
|
|
statusText = _translate(
|
|
|
|
|
"MainWindow",
|
|
|
|
|
"Problem: The work demanded by the recipient is more difficult than you are willing to do. %1").arg(
|
|
|
|
|
l10n.formatTimestamp(lastactiontime))
|
|
|
|
|
elif status == 'badkey':
|
|
|
|
|
statusText = _translate("MainWindow", "Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1").arg(
|
|
|
|
|
l10n.formatTimestamp(lastactiontime))
|
|
|
|
|
statusText = _translate(
|
|
|
|
|
"MainWindow",
|
|
|
|
|
"Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1").arg(
|
|
|
|
|
l10n.formatTimestamp(lastactiontime))
|
|
|
|
|
elif status == 'forcepow':
|
|
|
|
|
statusText = _translate(
|
|
|
|
|
"MainWindow", "Forced difficulty override. Send should start soon.")
|
|
|
|
@ -1088,6 +1168,8 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
return acct
|
|
|
|
|
|
|
|
|
|
def addMessageListItemInbox(self, tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
font = QtGui.QFont()
|
|
|
|
|
font.setBold(True)
|
|
|
|
|
if toAddress == str_broadcast_subscribers:
|
|
|
|
@ -1099,9 +1181,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
if acct is None:
|
|
|
|
|
acct = BMAccount(fromAddress)
|
|
|
|
|
acct.parseMessage(toAddress, fromAddress, subject, "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
items = []
|
|
|
|
|
#to
|
|
|
|
|
# to
|
|
|
|
|
MessageList_AddressWidget(items, toAddress, unicode(acct.toLabel, 'utf-8'), not read)
|
|
|
|
|
# from
|
|
|
|
|
MessageList_AddressWidget(items, fromAddress, unicode(acct.fromLabel, 'utf-8'), not read)
|
|
|
|
@ -1120,8 +1202,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.addMessageListItem(tableWidget, items)
|
|
|
|
|
return acct
|
|
|
|
|
|
|
|
|
|
# Load Sent items from database
|
|
|
|
|
def loadSent(self, tableWidget, account, where="", what=""):
|
|
|
|
|
"""Load Sent items from database"""
|
|
|
|
|
|
|
|
|
|
if tableWidget == self.ui.tableWidgetInboxSubscriptions:
|
|
|
|
|
tableWidget.setColumnHidden(0, True)
|
|
|
|
|
tableWidget.setColumnHidden(1, False)
|
|
|
|
@ -1153,8 +1236,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
tableWidget.horizontalHeaderItem(3).setText(_translate("MainWindow", "Sent", None))
|
|
|
|
|
tableWidget.setUpdatesEnabled(True)
|
|
|
|
|
|
|
|
|
|
# Load messages from database file
|
|
|
|
|
def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what="", unreadOnly = False):
|
|
|
|
|
def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what="", unreadOnly=False):
|
|
|
|
|
"""Load messages from database file"""
|
|
|
|
|
|
|
|
|
|
if folder == 'sent':
|
|
|
|
|
self.loadSent(tableWidget, account, where, what)
|
|
|
|
|
return
|
|
|
|
@ -1175,10 +1259,11 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
tableWidget.setRowCount(0)
|
|
|
|
|
|
|
|
|
|
queryreturn = helper_search.search_sql(xAddress, account, folder, where, what, unreadOnly)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for row in queryreturn:
|
|
|
|
|
msgfolder, msgid, toAddress, fromAddress, subject, received, read = row
|
|
|
|
|
self.addMessageListItemInbox(tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read)
|
|
|
|
|
self.addMessageListItemInbox(tableWidget, msgfolder, msgid, toAddress,
|
|
|
|
|
fromAddress, subject, received, read)
|
|
|
|
|
|
|
|
|
|
tableWidget.horizontalHeader().setSortIndicator(
|
|
|
|
|
3, QtCore.Qt.DescendingOrder)
|
|
|
|
@ -1187,9 +1272,10 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
tableWidget.horizontalHeaderItem(3).setText(_translate("MainWindow", "Received", None))
|
|
|
|
|
tableWidget.setUpdatesEnabled(True)
|
|
|
|
|
|
|
|
|
|
# create application indicator
|
|
|
|
|
def appIndicatorInit(self, app):
|
|
|
|
|
self.initTrayIcon("can-icon-24px-red.png", app)
|
|
|
|
|
def appIndicatorInit(self, this_app):
|
|
|
|
|
"""create application indicator"""
|
|
|
|
|
|
|
|
|
|
self.initTrayIcon("can-icon-24px-red.png", this_app)
|
|
|
|
|
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
|
|
|
|
|
QtCore.QObject.connect(self.tray, QtCore.SIGNAL(
|
|
|
|
|
traySignal), self.__icon_activated)
|
|
|
|
@ -1211,7 +1297,7 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.actionShow.setChecked(not BMConfigParser().getboolean(
|
|
|
|
|
'bitmessagesettings', 'startintray'))
|
|
|
|
|
self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow)
|
|
|
|
|
if not sys.platform[0:3] == 'win':
|
|
|
|
|
if sys.platform[0:3] != 'win':
|
|
|
|
|
m.addAction(self.actionShow)
|
|
|
|
|
|
|
|
|
|
# quiet mode
|
|
|
|
@ -1252,8 +1338,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.tray.setContextMenu(m)
|
|
|
|
|
self.tray.show()
|
|
|
|
|
|
|
|
|
|
# returns the number of unread messages and subscriptions
|
|
|
|
|
def getUnread(self):
|
|
|
|
|
"""returns the number of unread messages and subscriptions"""
|
|
|
|
|
|
|
|
|
|
counters = [0, 0]
|
|
|
|
|
|
|
|
|
|
queryreturn = sqlQuery('''
|
|
|
|
@ -1268,12 +1355,15 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
|
|
|
|
|
return counters
|
|
|
|
|
|
|
|
|
|
# play a sound
|
|
|
|
|
def playSound(self, category, label):
|
|
|
|
|
def playSound(self, category, label): # pylint: disable=inconsistent-return-statements
|
|
|
|
|
"""play a sound"""
|
|
|
|
|
|
|
|
|
|
# filename of the sound to be played
|
|
|
|
|
soundFilename = None
|
|
|
|
|
|
|
|
|
|
def _choose_ext(basename):
|
|
|
|
|
def _choose_ext(basename): # pylint: disable=inconsistent-return-statements
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
for ext in sound.extensions:
|
|
|
|
|
if os.path.isfile(os.extsep.join([basename, ext])):
|
|
|
|
|
return os.extsep + ext
|
|
|
|
@ -1295,24 +1385,23 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
# elapsed time since the last sound was played
|
|
|
|
|
dt = datetime.now() - self.lastSoundTime
|
|
|
|
|
# suppress sounds which are more frequent than the threshold
|
|
|
|
|
if dt.total_seconds() < self.maxSoundFrequencySec:
|
|
|
|
|
return
|
|
|
|
|
if not dt.total_seconds() < self.maxSoundFrequencySec:
|
|
|
|
|
|
|
|
|
|
# the sound is for an address which exists in the address book
|
|
|
|
|
if category is sound.SOUND_KNOWN:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/known'
|
|
|
|
|
# the sound is for an unknown address
|
|
|
|
|
elif category is sound.SOUND_UNKNOWN:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/unknown'
|
|
|
|
|
# initial connection sound
|
|
|
|
|
elif category is sound.SOUND_CONNECTED:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/connected'
|
|
|
|
|
# disconnected sound
|
|
|
|
|
elif category is sound.SOUND_DISCONNECTED:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/disconnected'
|
|
|
|
|
# sound when the connection status becomes green
|
|
|
|
|
elif category is sound.SOUND_CONNECTION_GREEN:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/green'
|
|
|
|
|
# the sound is for an address which exists in the address book
|
|
|
|
|
if category is sound.SOUND_KNOWN:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/known'
|
|
|
|
|
# the sound is for an unknown address
|
|
|
|
|
elif category is sound.SOUND_UNKNOWN:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/unknown'
|
|
|
|
|
# initial connection sound
|
|
|
|
|
elif category is sound.SOUND_CONNECTED:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/connected'
|
|
|
|
|
# disconnected sound
|
|
|
|
|
elif category is sound.SOUND_DISCONNECTED:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/disconnected'
|
|
|
|
|
# sound when the connection status becomes green
|
|
|
|
|
elif category is sound.SOUND_CONNECTION_GREEN:
|
|
|
|
|
soundFilename = state.appdata + 'sounds/green'
|
|
|
|
|
|
|
|
|
|
if soundFilename is None:
|
|
|
|
|
logger.warning("Probably wrong category number in playSound()")
|
|
|
|
@ -1336,13 +1425,14 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
|
|
|
|
|
self._player(soundFilename)
|
|
|
|
|
|
|
|
|
|
# Adapters and converters for QT <-> sqlite
|
|
|
|
|
def sqlInit(self):
|
|
|
|
|
"""Adapters and converters for QT <-> sqlite"""
|
|
|
|
|
|
|
|
|
|
register_adapter(QtCore.QByteArray, str)
|
|
|
|
|
|
|
|
|
|
# Try init the distro specific appindicator,
|
|
|
|
|
# for example the Ubuntu MessagingMenu
|
|
|
|
|
def indicatorInit(self):
|
|
|
|
|
""" Try init the distro specific appindicator, for example the Ubuntu MessagingMenu"""
|
|
|
|
|
|
|
|
|
|
def _noop_update(*args, **kwargs):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
@ -1352,8 +1442,9 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
logger.warning("No indicator plugin found")
|
|
|
|
|
self.indicatorUpdate = _noop_update
|
|
|
|
|
|
|
|
|
|
# initialise the message notifier
|
|
|
|
|
def notifierInit(self):
|
|
|
|
|
"""initialise the message notifier"""
|
|
|
|
|
|
|
|
|
|
def _simple_notify(
|
|
|
|
|
title, subtitle, category, label=None, icon=None):
|
|
|
|
|
self.tray.showMessage(title, subtitle, 1, 2000)
|
|
|
|
@ -1383,27 +1474,34 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
|
|
|
|
|
def notifierShow(
|
|
|
|
|
self, title, subtitle, category, label=None, icon=None):
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
self.playSound(category, label)
|
|
|
|
|
self._notifier(
|
|
|
|
|
unicode(title), unicode(subtitle), category, label, icon)
|
|
|
|
|
|
|
|
|
|
# tree
|
|
|
|
|
def treeWidgetKeyPressEvent(self, event):
|
|
|
|
|
"""tree"""
|
|
|
|
|
|
|
|
|
|
return self.handleKeyPress(event, self.getCurrentTreeWidget())
|
|
|
|
|
|
|
|
|
|
# inbox / sent
|
|
|
|
|
def tableWidgetKeyPressEvent(self, event):
|
|
|
|
|
"""inbox / sent"""
|
|
|
|
|
|
|
|
|
|
return self.handleKeyPress(event, self.getCurrentMessagelist())
|
|
|
|
|
|
|
|
|
|
# messageview
|
|
|
|
|
def textEditKeyPressEvent(self, event):
|
|
|
|
|
"""messageview"""
|
|
|
|
|
|
|
|
|
|
return self.handleKeyPress(event, self.getCurrentMessageTextedit())
|
|
|
|
|
|
|
|
|
|
def handleKeyPress(self, event, focus = None):
|
|
|
|
|
def handleKeyPress(self, event, focus=None): # pylint: disable=inconsistent-return-statements
|
|
|
|
|
"""TBC"""
|
|
|
|
|
|
|
|
|
|
messagelist = self.getCurrentMessagelist()
|
|
|
|
|
folder = self.getCurrentFolder()
|
|
|
|
|
if event.key() == QtCore.Qt.Key_Delete:
|
|
|
|
|
if isinstance (focus, MessageView) or isinstance(focus, QtGui.QTableWidget):
|
|
|
|
|
if isinstance(focus, (MessageView, QtGui.QTableWidget)):
|
|
|
|
|
if folder == "sent":
|
|
|
|
|
self.on_action_SentTrash()
|
|
|
|
|
else:
|
|
|
|
@ -1439,60 +1537,116 @@ class MyForm(settingsmixin.SMainWindow):
|
|
|
|
|
self.ui.lineEditTo.setFocus()
|
|
|
|
|
event.ignore()
|
|
|
|
|
elif event.key() == QtCore.Qt.Key_F:
|
|
|
|
|
searchline = self.getCurrentSearchLine(retObj = True)
|
|
|
|
|
searchline = self.getCurrentSearchLine(retObj=True)
|
|
|
|
|
if searchline:
|
|
|
|
|
searchline.setFocus()
|
|
|
|
|
event.ignore()
|
|
|
|
|
if not event.isAccepted():
|
|
|
|
|
return
|
|
|
|
|
if isinstance (focus, MessageView):
|
|
|
|
|
if isinstance(focus, MessageView):
|
|
|
|
|
return MessageView.keyPressEvent(focus, event)
|
|
|
|
|
elif isinstance (focus, QtGui.QTableWidget):
|
|
|
|
|
elif isinstance(focus, QtGui.QTableWidget):
|
|
|
|
|
return QtGui.QTableWidget.keyPressEvent(focus, event)
|
|
|
|
|
elif isinstance (focus, QtGui.QTreeWidget):
|
|
|
|
|
elif isinstance(focus, QtGui.QTreeWidget):
|
|
|
|
|
return QtGui.QTreeWidget.keyPressEvent(focus, event)
|
|
|
|
|
|
|
|
|
|
# menu button 'manage keys'
|
|
|
|
|
def click_actionManageKeys(self):
|
|
|
|
|
"""menu button 'manage keys'"""
|
|
|
|
|
|
|
|
|
|
if 'darwin' in sys.platform or 'linux' in sys.platform:
|
|
|
|
|
if state.appdata == '':
|
|
|
|
|
# reply = QtGui.QMessageBox.information(self, 'keys.dat?','You
|
|
|
|
|
# may manage your keys by editing the keys.dat file stored in
|
|
|
|
|
# the same directory as this program. It is important that you
|
|
|
|
|
# back up this file.', QMessageBox.Ok)
|
|
|
|
|
reply = QtGui.QMessageBox.information(self, 'keys.dat?', _translate(
|
|
|
|
|
"MainWindow", "You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file."), QtGui.QMessageBox.Ok)
|
|
|
|
|
reply = QtGui.QMessageBox.information(
|
|
|
|
|
self,
|
|
|
|
|
'keys.dat?',
|
|
|
|
|
_translate(
|
|
|
|
|
"MainWindow",
|
|
|
|
|
("You may manage your keys by editing the keys.dat file stored in the same directory as this "
|
|
|
|
|
"program. It is important that you back up this file.")),
|
|
|
|
|
QtGui.QMessageBox.Ok)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
QtGui.QMessageBox.information(self, 'keys.dat?', _translate(
|
|
|
|
|
"MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file.").arg(state.appdata), QtGui.QMessageBox.Ok)
|
|
|
|
|
QtGui.QMessageBox.information(
|
|
|
|
|
self,
|
|
|
|
|
'keys.dat?',
|
|
|
|
|
_translate(
|
|
|
|
|
"MainWindow",
|
|
|
|
|
("You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important "
|
|
|
|
|
"that you back up this file.")).arg(
|
|
|
|
|
state.appdata),
|
|
|
|
|
QtGui.QMessageBox.Ok)
|
|
|
|
|
elif sys.platform == 'win32' or sys.platform == 'win64':
|
|
|
|
|
if state.appdata == '':
|
|
|
|
|
reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate(
|
|
|
|
|
"MainWindow", "You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
|
|
|
|
reply = QtGui.QMessageBox.question(
|
|
|
|
|
self,
|
|
|
|
|
_translate(
|
|
|
|
|
"MainWindow",
|
|
|
|
|
"Open keys.dat?"),
|
|
|
|
|
_translate(
|
|
|
|
|
"MainWindow",
|
|
|
|
|
("You may manage your keys by editing the keys.dat file stored in the same directory as this "
|
|