manually merged changes in
This commit is contained in:
commit
0842679314
3
Makefile
3
Makefile
|
@ -13,7 +13,6 @@ source:
|
||||||
install:
|
install:
|
||||||
mkdir -m 755 -p $(DEST_APP)
|
mkdir -m 755 -p $(DEST_APP)
|
||||||
mkdir -m 755 -p $(DEST_SHARE)/applications
|
mkdir -m 755 -p $(DEST_SHARE)/applications
|
||||||
mkdir -m 755 -p $(DEST_SHARE)/applications/$(APP)
|
|
||||||
mkdir -m 755 -p $(DEST_APP)/images
|
mkdir -m 755 -p $(DEST_APP)/images
|
||||||
mkdir -m 755 -p $(DEST_APP)/pyelliptic
|
mkdir -m 755 -p $(DEST_APP)/pyelliptic
|
||||||
mkdir -m 755 -p $(DEST_APP)/socks
|
mkdir -m 755 -p $(DEST_APP)/socks
|
||||||
|
@ -37,7 +36,7 @@ install:
|
||||||
install -m 644 src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt
|
install -m 644 src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt
|
||||||
install -m 755 debian/pybm /usr/bin/pybitmessage
|
install -m 755 debian/pybm /usr/bin/pybitmessage
|
||||||
|
|
||||||
install -m 644 desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP)/$(APP).desktop
|
install -m 644 desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP).desktop
|
||||||
install -m 644 src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png
|
install -m 644 src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png
|
||||||
install -m 644 desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg
|
install -m 644 desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg
|
||||||
install -m 644 desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg
|
install -m 644 desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg
|
||||||
|
|
2
debian/changelog
vendored
2
debian/changelog
vendored
|
@ -1,4 +1,4 @@
|
||||||
pybitmessage (0.3.0-1) unstable; urgency=low
|
pybitmessage (0.3.0-1) raring; urgency=low
|
||||||
|
|
||||||
* Added new API function: getStatus
|
* Added new API function: getStatus
|
||||||
|
|
||||||
|
|
4
debian/control
vendored
4
debian/control
vendored
|
@ -2,7 +2,7 @@ Source: pybitmessage
|
||||||
Section: contrib/comm
|
Section: contrib/comm
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: Jonathan Warren <jonathan@bitmessage.org>
|
Maintainer: Jonathan Warren <jonathan@bitmessage.org>
|
||||||
Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev
|
Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, libmessaging-menu-dev
|
||||||
Standards-Version: 3.9.2
|
Standards-Version: 3.9.2
|
||||||
Homepage: https://bitmessage.org/
|
Homepage: https://bitmessage.org/
|
||||||
Vcs-Browser: https://github.com/Bitmessage/PyBitmessage
|
Vcs-Browser: https://github.com/Bitmessage/PyBitmessage
|
||||||
|
@ -10,7 +10,7 @@ Vcs-Git: https://github.com/Bitmessage/PyBitmessage.git
|
||||||
|
|
||||||
Package: pybitmessage
|
Package: pybitmessage
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Depends: ${misc:Depends}, python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev
|
Depends: ${misc:Depends}, python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, libmessaging-menu-dev
|
||||||
Description: Send encrypted messages to another person or to many subscribers
|
Description: Send encrypted messages to another person or to many subscribers
|
||||||
Bitmessage is a P2P communications protocol used to send encrypted messages
|
Bitmessage is a P2P communications protocol used to send encrypted messages
|
||||||
to another person or to many subscribers. It is decentralized and trustless,
|
to another person or to many subscribers. It is decentralized and trustless,
|
||||||
|
|
1
debian/files
vendored
1
debian/files
vendored
|
@ -1 +0,0 @@
|
||||||
pybitmessage_0.3.0-1_all.deb contrib/comm extra
|
|
4
debian/pybm
vendored
4
debian/pybm
vendored
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
cd /usr/share/pybitmessage
|
cd /usr/share/pybitmessage
|
||||||
python bitmessagemain.py
|
exec python bitmessagemain.py
|
||||||
|
|
||||||
|
|
4
debian/rules
vendored
4
debian/rules
vendored
|
@ -20,11 +20,11 @@ install: build clean
|
||||||
dh_testroot
|
dh_testroot
|
||||||
dh_prep
|
dh_prep
|
||||||
dh_installdirs
|
dh_installdirs
|
||||||
|
|
||||||
mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr
|
mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr
|
||||||
mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr/bin
|
mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr/bin
|
||||||
mkdir -m 755 -p $(DEST_APP)
|
mkdir -m 755 -p $(DEST_APP)
|
||||||
mkdir -m 755 -p $(DEST_SHARE)/applications
|
mkdir -m 755 -p $(DEST_SHARE)/applications
|
||||||
mkdir -m 755 -p $(DEST_SHARE)/applications/$(APP)
|
|
||||||
mkdir -m 755 -p $(DEST_APP)/images
|
mkdir -m 755 -p $(DEST_APP)/images
|
||||||
mkdir -m 755 -p $(DEST_APP)/pyelliptic
|
mkdir -m 755 -p $(DEST_APP)/pyelliptic
|
||||||
mkdir -m 755 -p $(DEST_APP)/socks
|
mkdir -m 755 -p $(DEST_APP)/socks
|
||||||
|
@ -48,7 +48,7 @@ install: build clean
|
||||||
install -m 644 $(CURDIR)/src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt
|
install -m 644 $(CURDIR)/src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt
|
||||||
install -m 755 $(CURDIR)/debian/pybm $(DEST_MAIN)/pybitmessage
|
install -m 755 $(CURDIR)/debian/pybm $(DEST_MAIN)/pybitmessage
|
||||||
|
|
||||||
install -m 644 $(CURDIR)/desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP)/$(APP).desktop
|
install -m 644 $(CURDIR)/desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP).desktop
|
||||||
install -m 644 $(CURDIR)/src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png
|
install -m 644 $(CURDIR)/src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png
|
||||||
install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg
|
install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg
|
||||||
install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg
|
install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg
|
||||||
|
|
3
debian/source/include-binaries
vendored
3
debian/source/include-binaries
vendored
|
@ -6,6 +6,9 @@ src/images/redicon.png
|
||||||
src/images/subscriptions.png
|
src/images/subscriptions.png
|
||||||
src/images/blacklist.png
|
src/images/blacklist.png
|
||||||
src/images/can-icon-24px.png
|
src/images/can-icon-24px.png
|
||||||
|
src/images/can-icon-24px-red.png
|
||||||
|
src/images/can-icon-24px-yellow.png
|
||||||
|
src/images/can-icon-24px-green.png
|
||||||
src/images/identities.png
|
src/images/identities.png
|
||||||
src/images/yellowicon.png
|
src/images/yellowicon.png
|
||||||
src/images/inbox.png
|
src/images/inbox.png
|
||||||
|
|
|
@ -2,8 +2,29 @@
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=PyBitmessage
|
Name=PyBitmessage
|
||||||
GenericName=PyBitmessage
|
GenericName=PyBitmessage
|
||||||
|
X-GNOME-FullName=PyBitmessage Secure Messaging
|
||||||
Comment=Send encrypted messages to another person or to many subscribers
|
Comment=Send encrypted messages to another person or to many subscribers
|
||||||
Exec=pybitmessage %U
|
Exec=pybitmessage %U
|
||||||
Icon=pybitmessage
|
Icon=pybitmessage
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Categories=Network
|
Categories=Network;Email;Application
|
||||||
|
Keywords=Email;E-mail;Newsgroup;Messaging
|
||||||
|
X-MessagingMenu-UsesChatSection=true
|
||||||
|
X-Ubuntu-Gettext-Domain=pybitmessage
|
||||||
|
|
||||||
|
Actions=Send;Subscribe;AddressBook
|
||||||
|
|
||||||
|
[Desktop Action Send]
|
||||||
|
Name=Send
|
||||||
|
Exec=pybitmessage -s
|
||||||
|
OnlyShowIn=Unity;
|
||||||
|
|
||||||
|
[Desktop Action Subscribe]
|
||||||
|
Name=Subscribe
|
||||||
|
Exec=pybitmessage -b
|
||||||
|
OnlyShowIn=Unity;
|
||||||
|
|
||||||
|
[Desktop Action AddressBook]
|
||||||
|
Name=Address Book
|
||||||
|
Exec=pybitmessage -a
|
||||||
|
OnlyShowIn=Unity;
|
|
@ -47,7 +47,7 @@ import signal #Used to capture a Ctrl-C keypress so that Bitmessage can shutdown
|
||||||
from SimpleXMLRPCServer import *
|
from SimpleXMLRPCServer import *
|
||||||
import json
|
import json
|
||||||
from subprocess import call #used when the API must execute an outside program
|
from subprocess import call #used when the API must execute an outside program
|
||||||
|
import singleton
|
||||||
|
|
||||||
#For each stream to which we connect, several outgoingSynSender threads will exist and will collectively create 8 connections with peers.
|
#For each stream to which we connect, several outgoingSynSender threads will exist and will collectively create 8 connections with peers.
|
||||||
class outgoingSynSender(threading.Thread):
|
class outgoingSynSender(threading.Thread):
|
||||||
|
@ -3810,6 +3810,9 @@ if useVeryEasyProofOfWorkForTesting:
|
||||||
shared.networkDefaultPayloadLengthExtraBytes = int(shared.networkDefaultPayloadLengthExtraBytes / 7000)
|
shared.networkDefaultPayloadLengthExtraBytes = int(shared.networkDefaultPayloadLengthExtraBytes / 7000)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# is the application already running? If yes then exit.
|
||||||
|
thisapp = singleton.singleinstance()
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
#signal.signal(signal.SIGINT, signal.SIG_DFL)
|
#signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
|
@ -3857,6 +3860,7 @@ if __name__ == "__main__":
|
||||||
shared.config.set('bitmessagesettings','messagesencrypted','false')
|
shared.config.set('bitmessagesettings','messagesencrypted','false')
|
||||||
shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte',str(shared.networkDefaultProofOfWorkNonceTrialsPerByte))
|
shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte',str(shared.networkDefaultProofOfWorkNonceTrialsPerByte))
|
||||||
shared.config.set('bitmessagesettings','defaultpayloadlengthextrabytes',str(shared.networkDefaultPayloadLengthExtraBytes))
|
shared.config.set('bitmessagesettings','defaultpayloadlengthextrabytes',str(shared.networkDefaultPayloadLengthExtraBytes))
|
||||||
|
shared.config.set('bitmessagesettings','minimizeonclose','true')
|
||||||
|
|
||||||
if storeConfigFilesInSameDirectoryAsProgramByDefault:
|
if storeConfigFilesInSameDirectoryAsProgramByDefault:
|
||||||
#Just use the same directory as the program and forget about the appdata folder
|
#Just use the same directory as the program and forget about the appdata folder
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PyQt4.QtCore import *
|
from PyQt4.QtCore import *
|
||||||
from PyQt4.QtGui import *
|
from PyQt4.QtGui import *
|
||||||
|
@ -5,6 +6,15 @@ except Exception, err:
|
||||||
print 'PyBitmessage requires PyQt. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).'
|
print 'PyBitmessage requires PyQt. 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
|
print 'Error message:', err
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
withMessagingMenu = False
|
||||||
|
try:
|
||||||
|
from gi.repository import MessagingMenu
|
||||||
|
from gi.repository import Notify
|
||||||
|
withMessagingMenu = True
|
||||||
|
except ImportError:
|
||||||
|
MessagingMenu = None
|
||||||
|
|
||||||
from addresses import *
|
from addresses import *
|
||||||
import shared
|
import shared
|
||||||
from bitmessageui import *
|
from bitmessageui import *
|
||||||
|
@ -22,8 +32,10 @@ import time
|
||||||
import os
|
import os
|
||||||
from pyelliptic.openssl import OpenSSL
|
from pyelliptic.openssl import OpenSSL
|
||||||
import pickle
|
import pickle
|
||||||
|
import platform
|
||||||
|
|
||||||
class MyForm(QtGui.QMainWindow):
|
class MyForm(QtGui.QMainWindow):
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QtGui.QWidget.__init__(self, parent)
|
QtGui.QWidget.__init__(self, parent)
|
||||||
self.ui = Ui_MainWindow()
|
self.ui = Ui_MainWindow()
|
||||||
|
@ -62,7 +74,7 @@ class MyForm(QtGui.QMainWindow):
|
||||||
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
|
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
|
||||||
QtCore.QObject.connect(self.trayIcon, QtCore.SIGNAL(traySignal), self.__icon_activated)
|
QtCore.QObject.connect(self.trayIcon, QtCore.SIGNAL(traySignal), self.__icon_activated)
|
||||||
menu = QtGui.QMenu()
|
menu = QtGui.QMenu()
|
||||||
self.exitAction = menu.addAction("Exit", self.close)
|
self.exitAction = menu.addAction("Quit", self.quit)
|
||||||
self.trayIcon.setContextMenu(menu)
|
self.trayIcon.setContextMenu(menu)
|
||||||
#I'm currently under the impression that Mac users have different expectations for the tray icon. They don't necessairly expect it to open the main window when clicked and they still expect a program showing a tray icon to also be in the dock.
|
#I'm currently under the impression that Mac users have different expectations for the tray icon. They don't necessairly expect it to open the main window when clicked and they still expect a program showing a tray icon to also be in the dock.
|
||||||
if 'darwin' in sys.platform:
|
if 'darwin' in sys.platform:
|
||||||
|
@ -71,7 +83,7 @@ class MyForm(QtGui.QMainWindow):
|
||||||
self.ui.labelSendBroadcastWarning.setVisible(False)
|
self.ui.labelSendBroadcastWarning.setVisible(False)
|
||||||
|
|
||||||
#FILE MENU and other buttons
|
#FILE MENU and other buttons
|
||||||
QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL("triggered()"), self.close)
|
QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL("triggered()"), self.quit)
|
||||||
QtCore.QObject.connect(self.ui.actionManageKeys, QtCore.SIGNAL("triggered()"), self.click_actionManageKeys)
|
QtCore.QObject.connect(self.ui.actionManageKeys, QtCore.SIGNAL("triggered()"), self.click_actionManageKeys)
|
||||||
QtCore.QObject.connect(self.ui.actionRegenerateDeterministicAddresses, QtCore.SIGNAL("triggered()"), self.click_actionRegenerateDeterministicAddresses)
|
QtCore.QObject.connect(self.ui.actionRegenerateDeterministicAddresses, QtCore.SIGNAL("triggered()"), self.click_actionRegenerateDeterministicAddresses)
|
||||||
QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL("clicked()"), self.click_NewAddressDialog)
|
QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL("clicked()"), self.click_NewAddressDialog)
|
||||||
|
@ -228,12 +240,13 @@ class MyForm(QtGui.QMainWindow):
|
||||||
shared.sqlSubmitQueue.put('')
|
shared.sqlSubmitQueue.put('')
|
||||||
queryreturn = shared.sqlReturnQueue.get()
|
queryreturn = shared.sqlReturnQueue.get()
|
||||||
shared.sqlLock.release()
|
shared.sqlLock.release()
|
||||||
|
str_broadcast_subscribers = '[Broadcast subscribers]'
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
msgid, toAddress, fromAddress, subject, received, message, read = row
|
msgid, toAddress, fromAddress, subject, received, message, read = row
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if toAddress == '[Broadcast subscribers]':
|
if toAddress == str_broadcast_subscribers:
|
||||||
toLabel = '[Broadcast subscribers]'
|
toLabel = str_broadcast_subscribers
|
||||||
else:
|
else:
|
||||||
toLabel = shared.config.get(toAddress, 'label')
|
toLabel = shared.config.get(toAddress, 'label')
|
||||||
except:
|
except:
|
||||||
|
@ -459,6 +472,27 @@ class MyForm(QtGui.QMainWindow):
|
||||||
#self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
|
#self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
|
||||||
#self.activateWindow()
|
#self.activateWindow()
|
||||||
|
|
||||||
|
|
||||||
|
# pointer to the application
|
||||||
|
#app = None
|
||||||
|
|
||||||
|
# show the application window
|
||||||
|
def appIndicatorShow(self):
|
||||||
|
if self.actionShow == None:
|
||||||
|
return
|
||||||
|
if not self.actionShow.isChecked():
|
||||||
|
self.actionShow.setChecked(True)
|
||||||
|
self.appIndicatorShowOrHideWindow()
|
||||||
|
|
||||||
|
# unchecks the show item on the application indicator
|
||||||
|
def appIndicatorHide(self):
|
||||||
|
if self.actionShow == None:
|
||||||
|
return
|
||||||
|
if self.actionShow.isChecked():
|
||||||
|
self.actionShow.setChecked(False)
|
||||||
|
self.appIndicatorShowOrHideWindow()
|
||||||
|
|
||||||
|
# application indicator show or hide
|
||||||
"""# application indicator show or hide
|
"""# application indicator show or hide
|
||||||
def appIndicatorShowBitmessage(self):
|
def appIndicatorShowBitmessage(self):
|
||||||
#if self.actionShow == None:
|
#if self.actionShow == None:
|
||||||
|
@ -470,33 +504,53 @@ class MyForm(QtGui.QMainWindow):
|
||||||
else:
|
else:
|
||||||
self.appIndicatorShowOrHideWindow()"""
|
self.appIndicatorShowOrHideWindow()"""
|
||||||
|
|
||||||
|
# returns the index of the oldest unread message
|
||||||
|
def getUnreadMessageIndex(self):
|
||||||
|
shared.sqlLock.acquire()
|
||||||
|
shared.sqlSubmitQueue.put('''SELECT msgid, received, read FROM inbox where folder='inbox' ORDER BY received DESC ''')
|
||||||
|
shared.sqlSubmitQueue.put('')
|
||||||
|
queryreturn = shared.sqlReturnQueue.get()
|
||||||
|
shared.sqlLock.release()
|
||||||
|
i = 0
|
||||||
|
index = 0
|
||||||
|
for row in queryreturn:
|
||||||
|
msgid, received, read = row
|
||||||
|
if not read:
|
||||||
|
index = i
|
||||||
|
i = i + 1
|
||||||
|
return index
|
||||||
|
|
||||||
|
# Show the program window and select inbox tab
|
||||||
|
def appIndicatorInbox(self, mm_app, source_id):
|
||||||
|
self.appIndicatorShow()
|
||||||
|
# select inbox
|
||||||
|
self.ui.tabWidget.setCurrentIndex(0)
|
||||||
|
# select unread message
|
||||||
|
self.ui.tableWidgetInbox.selectRow(self.getUnreadMessageIndex())
|
||||||
|
self.tableWidgetInboxItemClicked()
|
||||||
|
|
||||||
# Show the program window and select send tab
|
# Show the program window and select send tab
|
||||||
def appIndicatorSend(self):
|
def appIndicatorSend(self):
|
||||||
if not self.actionShow.isChecked():
|
self.appIndicatorShow()
|
||||||
self.actionShow.setChecked(True)
|
|
||||||
self.appIndicatorShowOrHideWindow()
|
|
||||||
self.ui.tabWidget.setCurrentIndex(1)
|
self.ui.tabWidget.setCurrentIndex(1)
|
||||||
|
|
||||||
# Show the program window and select subscriptions tab
|
# Show the program window and select subscriptions tab
|
||||||
def appIndicatorSubscribe(self):
|
def appIndicatorSubscribe(self):
|
||||||
if not self.actionShow.isChecked():
|
self.appIndicatorShow()
|
||||||
self.actionShow.setChecked(True)
|
|
||||||
self.appIndicatorShowOrHideWindow()
|
|
||||||
self.ui.tabWidget.setCurrentIndex(4)
|
self.ui.tabWidget.setCurrentIndex(4)
|
||||||
|
|
||||||
# Show the program window and select the address book tab
|
# Show the program window and select the address book tab
|
||||||
def appIndicatorAddressBook(self):
|
def appIndicatorAddressBook(self):
|
||||||
if not self.actionShow.isChecked():
|
self.appIndicatorShow()
|
||||||
self.actionShow.setChecked(True)
|
|
||||||
self.appIndicatorShowOrHideWindow()
|
|
||||||
self.ui.tabWidget.setCurrentIndex(5)
|
self.ui.tabWidget.setCurrentIndex(5)
|
||||||
|
|
||||||
# create application indicator
|
# create application indicator
|
||||||
def createAppIndicator(self,app):
|
def appIndicatorInit(self,app):
|
||||||
self.tray = QSystemTrayIcon(QtGui.QIcon("images/can-icon-24px.png"), app)
|
self.tray = QSystemTrayIcon(QtGui.QIcon("images/can-icon-24px-red.png"), app)
|
||||||
if sys.platform[0:3] == 'win':
|
if sys.platform[0:3] == 'win':
|
||||||
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
|
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
|
||||||
QtCore.QObject.connect(self.tray, QtCore.SIGNAL(traySignal), self.__icon_activated)
|
QtCore.QObject.connect(self.tray, QtCore.SIGNAL(traySignal), self.__icon_activated)
|
||||||
|
|
||||||
m = QMenu()
|
m = QMenu()
|
||||||
|
|
||||||
self.actionStatus = QtGui.QAction('Not Connected',m,checkable=False)
|
self.actionStatus = QtGui.QAction('Not Connected',m,checkable=False)
|
||||||
|
@ -509,7 +563,7 @@ class MyForm(QtGui.QMainWindow):
|
||||||
|
|
||||||
# show bitmessage
|
# show bitmessage
|
||||||
self.actionShow = QtGui.QAction('Show Bitmessage',m,checkable=True)
|
self.actionShow = QtGui.QAction('Show Bitmessage',m,checkable=True)
|
||||||
self.actionShow.setChecked(True)
|
self.actionShow.setChecked(not shared.config.getboolean('bitmessagesettings', 'startintray'))
|
||||||
self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow)
|
self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow)
|
||||||
if not sys.platform[0:3] == 'win':
|
if not sys.platform[0:3] == 'win':
|
||||||
m.addAction(self.actionShow)
|
m.addAction(self.actionShow)
|
||||||
|
@ -535,15 +589,133 @@ class MyForm(QtGui.QMainWindow):
|
||||||
m.addAction(actionSeparator)
|
m.addAction(actionSeparator)
|
||||||
|
|
||||||
# Quit
|
# Quit
|
||||||
m.addAction("Quit", self.close)
|
m.addAction("Quit", self.quit)
|
||||||
|
|
||||||
self.tray.setContextMenu(m)
|
self.tray.setContextMenu(m)
|
||||||
self.tray.show()
|
self.tray.show()
|
||||||
if shared.config.getboolean('bitmessagesettings', 'startintray'):
|
|
||||||
#myapp.trayIcon.show()#This option seems to have been obsoleted by https://github.com/Bitmessage/PyBitmessage/pull/133/files
|
# Ubuntu Messaging menu object
|
||||||
self.actionShow.setChecked(False)
|
mmapp = None
|
||||||
self.appIndicatorShowOrHideWindow()
|
|
||||||
#if sys.platform[0:3] == 'win':
|
# is the operating system Ubuntu?
|
||||||
# myapp.setWindowFlags(Qt.ToolTip)
|
def isUbuntu(self):
|
||||||
|
for entry in platform.uname():
|
||||||
|
if "Ubuntu" in entry:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# returns the number of unread messages and subscriptions
|
||||||
|
def getUnread(self):
|
||||||
|
str_broadcast_subscribers = '[Broadcast subscribers]'
|
||||||
|
|
||||||
|
unreadMessages = 0
|
||||||
|
unreadSubscriptions = 0
|
||||||
|
|
||||||
|
shared.sqlLock.acquire()
|
||||||
|
shared.sqlSubmitQueue.put('''SELECT msgid, toaddress, read FROM inbox where folder='inbox' ''')
|
||||||
|
shared.sqlSubmitQueue.put('')
|
||||||
|
queryreturn = shared.sqlReturnQueue.get()
|
||||||
|
shared.sqlLock.release()
|
||||||
|
for row in queryreturn:
|
||||||
|
msgid, toAddress, read = row
|
||||||
|
|
||||||
|
try:
|
||||||
|
if toAddress == str_broadcast_subscribers:
|
||||||
|
toLabel = str_broadcast_subscribers
|
||||||
|
else:
|
||||||
|
toLabel = shared.config.get(toAddress, 'label')
|
||||||
|
except:
|
||||||
|
toLabel = ''
|
||||||
|
if toLabel == '':
|
||||||
|
toLabel = toAddress
|
||||||
|
|
||||||
|
if not read:
|
||||||
|
if toLabel == str_broadcast_subscribers:
|
||||||
|
# increment the unread subscriptions
|
||||||
|
unreadSubscriptions = unreadSubscriptions + 1
|
||||||
|
else:
|
||||||
|
# increment the unread messages
|
||||||
|
unreadMessages = unreadMessages + 1
|
||||||
|
return unreadMessages, unreadSubscriptions
|
||||||
|
|
||||||
|
# show the number of unread messages and subscriptions on the messaging menu
|
||||||
|
def ubuntuMessagingMenuUnread(self, drawAttention):
|
||||||
|
unreadMessages, unreadSubscriptions = self.getUnread()
|
||||||
|
# unread messages
|
||||||
|
if unreadMessages > 0:
|
||||||
|
self.mmapp.append_source("Messages", None, "Messages (" + str(unreadMessages) + ")")
|
||||||
|
if drawAttention:
|
||||||
|
self.mmapp.draw_attention("Messages")
|
||||||
|
|
||||||
|
# unread subscriptions
|
||||||
|
if unreadSubscriptions > 0:
|
||||||
|
self.mmapp.append_source("Subscriptions", None, "Subscriptions (" + str(unreadSubscriptions) + ")")
|
||||||
|
if drawAttention:
|
||||||
|
self.mmapp.draw_attention("Subscriptions")
|
||||||
|
|
||||||
|
# initialise the Ubuntu messaging menu
|
||||||
|
def ubuntuMessagingMenuInit(self):
|
||||||
|
global withMessagingMenu
|
||||||
|
|
||||||
|
# if this isn't ubuntu then don't do anything
|
||||||
|
if not self.isUbuntu():
|
||||||
|
return
|
||||||
|
|
||||||
|
# has messageing menu been installed
|
||||||
|
if not withMessagingMenu:
|
||||||
|
print 'WARNING: MessagingMenu is not available. Is libmessaging-menu-dev installed?'
|
||||||
|
return
|
||||||
|
|
||||||
|
# create the menu server
|
||||||
|
if withMessagingMenu:
|
||||||
|
try:
|
||||||
|
self.mmapp = MessagingMenu.App(desktop_id='pybitmessage.desktop')
|
||||||
|
self.mmapp.register()
|
||||||
|
self.mmapp.connect('activate-source', self.appIndicatorInbox)
|
||||||
|
self.ubuntuMessagingMenuUnread(True)
|
||||||
|
except Exception:
|
||||||
|
withMessagingMenu = False
|
||||||
|
print 'WARNING: messaging menu disabled'
|
||||||
|
|
||||||
|
# update the Ubuntu messaging menu
|
||||||
|
def ubuntuMessagingMenuUpdate(self, drawAttention):
|
||||||
|
global withMessagingMenu
|
||||||
|
|
||||||
|
# if this isn't ubuntu then don't do anything
|
||||||
|
if not self.isUbuntu():
|
||||||
|
return
|
||||||
|
|
||||||
|
# has messageing menu been installed
|
||||||
|
if not withMessagingMenu:
|
||||||
|
print 'WARNING: messaging menu disabled or libmessaging-menu-dev not installed'
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove previous messages and subscriptions entries, then recreate them
|
||||||
|
# There might be a better way to do it than this
|
||||||
|
if self.mmapp.has_source("Messages"):
|
||||||
|
self.mmapp.remove_source("Messages")
|
||||||
|
|
||||||
|
if self.mmapp.has_source("Subscriptions"):
|
||||||
|
self.mmapp.remove_source("Subscriptions")
|
||||||
|
|
||||||
|
# update the menu entries
|
||||||
|
self.ubuntuMessagingMenuUnread(drawAttention)
|
||||||
|
|
||||||
|
# initialise the message notifier
|
||||||
|
def notifierInit(self):
|
||||||
|
global withMessagingMenu
|
||||||
|
if withMessagingMenu:
|
||||||
|
Notify.init('pybitmessage')
|
||||||
|
|
||||||
|
# shows a notification
|
||||||
|
def notifierShow(self, title, subtitle):
|
||||||
|
global withMessagingMenu
|
||||||
|
if withMessagingMenu:
|
||||||
|
n = Notify.Notification.new(title, subtitle,'notification-message-email')
|
||||||
|
n.show()
|
||||||
|
return
|
||||||
|
# Show with tray
|
||||||
|
self.trayIcon.showMessage(title, subtitle, 1, 2000)
|
||||||
|
|
||||||
def tableWidgetInboxKeyPressEvent(self,event):
|
def tableWidgetInboxKeyPressEvent(self,event):
|
||||||
if event.key() == QtCore.Qt.Key_Delete:
|
if event.key() == QtCore.Qt.Key_Delete:
|
||||||
|
@ -598,10 +770,7 @@ class MyForm(QtGui.QMainWindow):
|
||||||
if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform:
|
if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform:
|
||||||
if event.type() == QtCore.QEvent.WindowStateChange:
|
if event.type() == QtCore.QEvent.WindowStateChange:
|
||||||
if self.windowState() & QtCore.Qt.WindowMinimized:
|
if self.windowState() & QtCore.Qt.WindowMinimized:
|
||||||
self.hide()
|
self.appIndicatorHide()
|
||||||
|
|
||||||
#self.trayIcon.show() #This may have been obsoleted by https://github.com/Bitmessage/PyBitmessage/issues/135
|
|
||||||
#self.hidden = True
|
|
||||||
if 'win32' in sys.platform or 'win64' in sys.platform:
|
if 'win32' in sys.platform or 'win64' in sys.platform:
|
||||||
self.setWindowFlags(Qt.ToolTip)
|
self.setWindowFlags(Qt.ToolTip)
|
||||||
elif event.oldState() & QtCore.Qt.WindowMinimized:
|
elif event.oldState() & QtCore.Qt.WindowMinimized:
|
||||||
|
@ -688,27 +857,47 @@ class MyForm(QtGui.QMainWindow):
|
||||||
elif len(shared.connectedHostsList) == 0:
|
elif len(shared.connectedHostsList) == 0:
|
||||||
self.setStatusIcon('red')
|
self.setStatusIcon('red')
|
||||||
|
|
||||||
|
# Indicates whether or not there is a connection to the Bitmessage network
|
||||||
|
connected = False
|
||||||
|
|
||||||
def setStatusIcon(self,color):
|
def setStatusIcon(self,color):
|
||||||
|
global withMessagingMenu
|
||||||
#print 'setting status icon color'
|
#print 'setting status icon color'
|
||||||
if color == 'red':
|
if color == 'red':
|
||||||
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/redicon.png"))
|
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/redicon.png"))
|
||||||
shared.statusIconColor = 'red'
|
shared.statusIconColor = 'red'
|
||||||
#if self.actionStatus != None:
|
# if the connection is lost then show a notification
|
||||||
|
if self.connected:
|
||||||
|
self.notifierShow('PyBitmessage','Connection lost')
|
||||||
|
self.connected = False
|
||||||
|
|
||||||
|
if self.actionStatus != None:
|
||||||
self.actionStatus.setText('Not Connected')
|
self.actionStatus.setText('Not Connected')
|
||||||
|
self.tray.setIcon(QtGui.QIcon("images/can-icon-24px-red.png"))
|
||||||
|
self.trayIcon.show()
|
||||||
if color == 'yellow':
|
if color == 'yellow':
|
||||||
if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.':
|
if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.':
|
||||||
self.statusBar().showMessage('')
|
self.statusBar().showMessage('')
|
||||||
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png"))
|
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png"))
|
||||||
shared.statusIconColor = 'yellow'
|
shared.statusIconColor = 'yellow'
|
||||||
#if self.actionStatus != None:
|
# if a new connection has been established then show a notification
|
||||||
|
if not self.connected:
|
||||||
|
self.notifierShow('PyBitmessage','Connected')
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
|
if self.actionStatus != None:
|
||||||
self.actionStatus.setText('Connected')
|
self.actionStatus.setText('Connected')
|
||||||
|
self.tray.setIcon(QtGui.QIcon("images/can-icon-24px-yellow.png"))
|
||||||
if color == 'green':
|
if color == 'green':
|
||||||
if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.':
|
if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.':
|
||||||
self.statusBar().showMessage('')
|
self.statusBar().showMessage('')
|
||||||
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/greenicon.png"))
|
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/greenicon.png"))
|
||||||
shared.statusIconColor = 'green'
|
shared.statusIconColor = 'green'
|
||||||
#if self.actionStatus != None:
|
self.connected = True
|
||||||
|
|
||||||
|
if self.actionStatus != None:
|
||||||
self.actionStatus.setText('Connected')
|
self.actionStatus.setText('Connected')
|
||||||
|
self.tray.setIcon(QtGui.QIcon("images/can-icon-24px-green.png"))
|
||||||
|
|
||||||
def updateSentItemStatusByHash(self,toRipe,textToDisplay):
|
def updateSentItemStatusByHash(self,toRipe,textToDisplay):
|
||||||
for i in range(self.ui.tableWidgetSent.rowCount()):
|
for i in range(self.ui.tableWidgetSent.rowCount()):
|
||||||
|
@ -1072,11 +1261,11 @@ class MyForm(QtGui.QMainWindow):
|
||||||
if fromLabel == '':
|
if fromLabel == '':
|
||||||
newItem = QtGui.QTableWidgetItem(unicode(fromAddress,'utf-8'))
|
newItem = QtGui.QTableWidgetItem(unicode(fromAddress,'utf-8'))
|
||||||
if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'):
|
if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'):
|
||||||
self.trayIcon.showMessage('New Message', 'New message from '+ fromAddress, 1, 2000)
|
self.notifierShow('New Message', 'From '+ fromAddress)
|
||||||
else:
|
else:
|
||||||
newItem = QtGui.QTableWidgetItem(unicode(fromLabel,'utf-8'))
|
newItem = QtGui.QTableWidgetItem(unicode(fromLabel,'utf-8'))
|
||||||
if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'):
|
if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'):
|
||||||
self.trayIcon.showMessage('New Message', 'New message from '+fromLabel, 1, 2000)
|
self.notifierShow('New Message', 'From ' + fromLabel)
|
||||||
newItem.setData(Qt.UserRole,str(fromAddress))
|
newItem.setData(Qt.UserRole,str(fromAddress))
|
||||||
newItem.setFont(font)
|
newItem.setFont(font)
|
||||||
self.ui.tableWidgetInbox.setItem(0,1,newItem)
|
self.ui.tableWidgetInbox.setItem(0,1,newItem)
|
||||||
|
@ -1096,6 +1285,7 @@ class MyForm(QtGui.QMainWindow):
|
||||||
else:
|
else:
|
||||||
self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(0,2).data(Qt.UserRole).toPyObject())"""
|
self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(0,2).data(Qt.UserRole).toPyObject())"""
|
||||||
self.ui.tableWidgetInbox.setSortingEnabled(True)
|
self.ui.tableWidgetInbox.setSortingEnabled(True)
|
||||||
|
self.ubuntuMessagingMenuUpdate(True)
|
||||||
|
|
||||||
def click_pushButtonAddAddressBook(self):
|
def click_pushButtonAddAddressBook(self):
|
||||||
self.NewSubscriptionDialogInstance = NewSubscriptionDialog(self)
|
self.NewSubscriptionDialogInstance = NewSubscriptionDialog(self)
|
||||||
|
@ -1400,25 +1590,43 @@ class MyForm(QtGui.QMainWindow):
|
||||||
else:
|
else:
|
||||||
print 'new address dialog box rejected'
|
print 'new address dialog box rejected'
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
|
# Quit selected from menu or application indicator
|
||||||
|
def quit(self):
|
||||||
'''quit_msg = "Are you sure you want to exit Bitmessage?"
|
'''quit_msg = "Are you sure you want to exit Bitmessage?"
|
||||||
reply = QtGui.QMessageBox.question(self, 'Message',
|
reply = QtGui.QMessageBox.question(self, 'Message',
|
||||||
quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
|
||||||
|
|
||||||
if reply == QtGui.QMessageBox.Yes:
|
if reply is QtGui.QMessageBox.No:
|
||||||
event.accept()
|
return
|
||||||
else:
|
'''
|
||||||
event.ignore()'''
|
|
||||||
shared.doCleanShutdown()
|
shared.doCleanShutdown()
|
||||||
#self.trayIcon.hide()
|
|
||||||
self.tray.hide()
|
self.tray.hide()
|
||||||
|
# unregister the messaging system
|
||||||
|
if self.mmapp is not None:
|
||||||
|
self.mmapp.unregister()
|
||||||
|
self.trayIcon.hide()
|
||||||
self.statusBar().showMessage('All done. Closing user interface...')
|
self.statusBar().showMessage('All done. Closing user interface...')
|
||||||
event.accept()
|
|
||||||
shared.printLock.acquire()
|
|
||||||
print 'Done. (passed event.accept())'
|
|
||||||
shared.printLock.release()
|
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
# window close event
|
||||||
|
def closeEvent(self, event):
|
||||||
|
self.appIndicatorHide()
|
||||||
|
minimizeonclose = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
minimizeonclose = shared.config.getboolean('bitmessagesettings', 'minimizeonclose')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if minimizeonclose:
|
||||||
|
# minimize the application
|
||||||
|
event.ignore()
|
||||||
|
else:
|
||||||
|
# quit the application
|
||||||
|
event.accept()
|
||||||
|
self.quit()
|
||||||
|
|
||||||
def on_action_InboxMessageForceHtml(self):
|
def on_action_InboxMessageForceHtml(self):
|
||||||
currentInboxRow = self.ui.tableWidgetInbox.currentRow()
|
currentInboxRow = self.ui.tableWidgetInbox.currentRow()
|
||||||
lines = self.ui.tableWidgetInbox.item(currentInboxRow,2).data(Qt.UserRole).toPyObject().split('\n')
|
lines = self.ui.tableWidgetInbox.item(currentInboxRow,2).data(Qt.UserRole).toPyObject().split('\n')
|
||||||
|
@ -2045,12 +2253,21 @@ class UISignaler(QThread):
|
||||||
else:
|
else:
|
||||||
sys.stderr.write('Command sent to UISignaler not recognized: %s\n' % command)
|
sys.stderr.write('Command sent to UISignaler not recognized: %s\n' % command)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
app = QtGui.QApplication(sys.argv)
|
app = QtGui.QApplication(sys.argv)
|
||||||
app.setStyleSheet("QStatusBar::item { border: 0px solid black }")
|
app.setStyleSheet("QStatusBar::item { border: 0px solid black }")
|
||||||
myapp = MyForm()
|
myapp = MyForm()
|
||||||
if not shared.config.getboolean('bitmessagesettings', 'startintray'):
|
|
||||||
|
if shared.config.getboolean('bitmessagesettings', 'startintray'):
|
||||||
|
if not myapp.isUbuntu():
|
||||||
|
myapp.trayIcon.show()
|
||||||
|
if 'win32' in sys.platform or 'win64' in sys.platform:
|
||||||
|
myapp.setWindowFlags(Qt.ToolTip)
|
||||||
|
else:
|
||||||
myapp.show()
|
myapp.show()
|
||||||
myapp.createAppIndicator(app)
|
|
||||||
|
myapp.appIndicatorInit(app)
|
||||||
|
myapp.ubuntuMessagingMenuInit()
|
||||||
|
myapp.notifierInit()
|
||||||
|
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
|
@ -515,7 +515,7 @@ class Ui_MainWindow(object):
|
||||||
self.menuHelp.setTitle(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8))
|
self.menuHelp.setTitle(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8))
|
||||||
self.actionImport_keys.setText(QtGui.QApplication.translate("MainWindow", "Import keys", None, QtGui.QApplication.UnicodeUTF8))
|
self.actionImport_keys.setText(QtGui.QApplication.translate("MainWindow", "Import keys", None, QtGui.QApplication.UnicodeUTF8))
|
||||||
self.actionManageKeys.setText(QtGui.QApplication.translate("MainWindow", "Manage keys", None, QtGui.QApplication.UnicodeUTF8))
|
self.actionManageKeys.setText(QtGui.QApplication.translate("MainWindow", "Manage keys", None, QtGui.QApplication.UnicodeUTF8))
|
||||||
self.actionExit.setText(QtGui.QApplication.translate("MainWindow", "Exit", None, QtGui.QApplication.UnicodeUTF8))
|
self.actionExit.setText(QtGui.QApplication.translate("MainWindow", "Quit", None, QtGui.QApplication.UnicodeUTF8))
|
||||||
self.actionHelp.setText(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8))
|
self.actionHelp.setText(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8))
|
||||||
self.actionAbout.setText(QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8))
|
self.actionAbout.setText(QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8))
|
||||||
self.actionSettings.setText(QtGui.QApplication.translate("MainWindow", "Settings", None, QtGui.QApplication.UnicodeUTF8))
|
self.actionSettings.setText(QtGui.QApplication.translate("MainWindow", "Settings", None, QtGui.QApplication.UnicodeUTF8))
|
||||||
|
|
|
@ -979,7 +979,7 @@ p, li { white-space: pre-wrap; }
|
||||||
</action>
|
</action>
|
||||||
<action name="actionExit">
|
<action name="actionExit">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Exit</string>
|
<string>Quit</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionHelp">
|
<action name="actionHelp">
|
||||||
|
|
BIN
src/images/can-icon-24px-green.png
Normal file
BIN
src/images/can-icon-24px-green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 885 B |
BIN
src/images/can-icon-24px-red.png
Normal file
BIN
src/images/can-icon-24px-red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 867 B |
BIN
src/images/can-icon-24px-yellow.png
Normal file
BIN
src/images/can-icon-24px-yellow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 872 B |
61
src/singleton.py
Normal file
61
src/singleton.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
import tempfile
|
||||||
|
from multiprocessing import Process
|
||||||
|
|
||||||
|
|
||||||
|
class singleinstance:
|
||||||
|
"""
|
||||||
|
Implements a single instance application by creating a lock file based on the full path to the script file.
|
||||||
|
|
||||||
|
This is based upon the singleton class from tendo https://github.com/pycontribs/tendo
|
||||||
|
which is under the Python Software Foundation License version 2
|
||||||
|
"""
|
||||||
|
def __init__(self, flavor_id=""):
|
||||||
|
import sys
|
||||||
|
self.initialized = False
|
||||||
|
basename = os.path.splitext(os.path.abspath(sys.argv[0]))[0].replace("/", "-").replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock'
|
||||||
|
self.lockfile = os.path.normpath(tempfile.gettempdir() + '/' + basename)
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
try:
|
||||||
|
# file already exists, we try to remove (in case previous execution was interrupted)
|
||||||
|
if os.path.exists(self.lockfile):
|
||||||
|
os.unlink(self.lockfile)
|
||||||
|
self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR)
|
||||||
|
except OSError:
|
||||||
|
type, e, tb = sys.exc_info()
|
||||||
|
if e.errno == 13:
|
||||||
|
print 'Another instance of this application is already running'
|
||||||
|
sys.exit(-1)
|
||||||
|
print(e.errno)
|
||||||
|
raise
|
||||||
|
else: # non Windows
|
||||||
|
import fcntl
|
||||||
|
self.fp = open(self.lockfile, 'w')
|
||||||
|
try:
|
||||||
|
fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
except IOError:
|
||||||
|
print 'Another instance of this application is already running'
|
||||||
|
sys.exit(-1)
|
||||||
|
self.initialized = True
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
import sys
|
||||||
|
if not self.initialized:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
if hasattr(self, 'fd'):
|
||||||
|
os.close(self.fd)
|
||||||
|
os.unlink(self.lockfile)
|
||||||
|
else:
|
||||||
|
import fcntl
|
||||||
|
fcntl.lockf(self.fp, fcntl.LOCK_UN)
|
||||||
|
if os.path.isfile(self.lockfile):
|
||||||
|
os.unlink(self.lockfile)
|
||||||
|
except Exception, e:
|
||||||
|
sys.exit(-1)
|
Reference in New Issue
Block a user