diff --git a/ArmoryQt.py b/ArmoryQt.py index cfcee1ef5..6bc8da002 100644 --- a/ArmoryQt.py +++ b/ArmoryQt.py @@ -65,6 +65,10 @@ def __init__(self, parent=None, settingsPath=None): self.extraHeartbeatFunctions = [] + self.lblArmoryStatus = QRichLabel('Offline', \ + doWrap=False) + self.statusBar().insertPermanentWidget(0, self.lblArmoryStatus) + # Keep a persistent printer object for paper backups self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) @@ -746,9 +750,13 @@ def loadBlockchain(self): self.ledgerSize = len(self.combinedLedger) print 'Ledger entries:', len(self.combinedLedger), 'Max Block:', self.latestBlockNum self.statusBar().showMessage('Blockchain loaded, wallets sync\'d!', 10000) + self.lblArmoryStatus.setText(\ + 'Connected (%s blocks) ' % self.latestBlockNum) + self.blkReceived = self.settings.getSettingOrSetDefault('LastBlkRecvTime', 0) else: self.statusBar().showMessage('! Blockchain loading failed !', 10000) + # This will force the table to refresh with new data self.walletModel.reset() @@ -1479,6 +1487,7 @@ def Heartbeat(self, nextBeatSec=2): # Check for new blocks in the blk0001.dat file if TheBDM.isInitialized(): newBlks = TheBDM.readBlkFileUpdate() + self.topTimestamp = TheBDM.getTopBlockHeader().getTimestamp() if newBlks>0: self.ledgerModel.reset() self.latestBlockNum = TheBDM.getTopBlockHeader().getBlockHeight() @@ -1495,6 +1504,23 @@ def Heartbeat(self, nextBeatSec=2): self.walletListChanged() self.NetworkingFactory.purgeMemoryPool() self.createCombinedLedger() + self.blkReceived = RightNow() + self.settings.set('LastBlkRecvTime', self.blkReceived) + self.lblArmoryStatus.setText(\ + 'Connected (%s blocks) ' % self.latestBlockNum) + + nowtime = RightNow() + blkRecvAgo = nowtime - self.blkReceived + blkStampAgo = nowtime - self.topTimestamp + #if self.usermode==USERMODE.Standard: + #self.lblArmoryStatus.setToolTip( 'Last block was received %s ago' % \ + #secondsToHumanTime(blkRecvAgo)) + #else: + ##self.lblArmoryStatus.setToolTip( \ + #'Last block was received %s ago \n(block timestamp is %s ago)' % \ + #(secondsToHumanTime(blkRecvAgo), secondsToHumanTime(blkStampAgo))) + self.lblArmoryStatus.setToolTip('Last block timestamp is %s ago' % \ + secondsToHumanTime(blkStampAgo)) #for wltID, wlt in self.walletMap.iteritems(): @@ -1503,6 +1529,7 @@ def Heartbeat(self, nextBeatSec=2): self.walletBalances[idx] = self.walletMap[wltID].getBalance() self.walletMap[wltID].checkWalletLockTimeout() + for func in self.extraHeartbeatFunctions: func() diff --git a/Using_Armory.README b/Using_Armory.README index 91b94e241..b0ba64ef0 100755 --- a/Using_Armory.README +++ b/Using_Armory.README @@ -54,6 +54,8 @@ that all features with an X in either column are accessible in SWIG. All OS: https://launchpad.net/qt4reactor Windows Only: qt4reactor relies on pywin32 (for win32event module) http://sourceforge.net/projects/pywin32/files/pywin32/Build216/ + + - pywin32 - py2exe (OPTIONAL - if you want to make a standalone executable in Windows) Windows: http://www.py2exe.org/ diff --git a/WindowsBuild.txt b/WindowsBuild.txt new file mode 100644 index 000000000..12c9207fc --- /dev/null +++ b/WindowsBuild.txt @@ -0,0 +1,52 @@ + +Make sure you have MSVS 2005 or 2008. [b]And if you are on a 64-bit system, make sure you select to install the x64 compilers under C++ options + +(The MSVS 2010 project is desperately out of date. Don't even bother trying it unless you're ready for a battle! However, I will be updating at some point in the future, I just want to make available the 2005 project first. + + +Install Git and TortoiseGit + http://code.google.com/p/msysgit/downloads/detail?name=Git-1.7.8-preview20111206.exe + http://code.google.com/p/tortoisegit/downloads/list + + +Clone the repo: + Right click on the directory where you want the code to go: select "Git clone..." + URL: git://github.com/etotheipi/BitcoinArmory.git + Click OK + + +While that's going, start downloading python-related stuff (there's a lot!) + +-- Download and install Python 2.6 or 2.7: + http://www.python.org/ftp/python/2.7.2/ +-- Download and install Python-Twisted: + http://twistedmatrix.com/trac/wiki/Downloads +-- Download and install zope.interface (for python-twisted): + http://pypi.python.org/pypi/zope.interface/3.8.0#downloads + Unless you know what to with an .egg file, you're going to have + to download the tar.gz, unpack it, and then execute setup.py via: + python setup.py install + +-- Download and UNPACK SWIG. + http://www.swig.org/download.html + + Move the inner-most swig-2.0.4 directory to BtcoinArmory/cppForSwig + (you should now see 3 subdirectories in cppForSwig dir: + cryptopp, reorgTest and swig-2.0.4): + +-- Download and full-install PyQt4: + http://www.riverbankcomputing.co.uk/software/pyqt/download + +-- (OPTIONAL) py2exe AND pywin32 AND MSVCP90.dll + http://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/ + http://sourceforge.net/projects/pywin32/files/pywin32/Build216/ + + MSVS is setup to create a standalone .exe of Armory if it finds + py2exe (otherwise it bails at the last build-step, but you can + still manually run ArmoryQt.py as long as the SWIG dir is in the + right place, and all packages are installed). pywin32 is needed + to + + + +During the last compilation step, you might observe an error about not finding 'python'. For whatever reason, python doesn't add itself to your PATH environment variable. You'll have to add ";C:\Python27\" or ";C:\Python26" to your path depending on which version you're using. Do this through control panel, search for "environment" and then edit the path and append the appropriate string. Reboot diff --git a/armoryengine.py b/armoryengine.py index f1bf2ef33..592f0af94 100644 --- a/armoryengine.py +++ b/armoryengine.py @@ -612,6 +612,29 @@ def unixTimeToFormatStr(unixTime, formatStr='%Y-%b-%d %I:%M%p'): dtstr = dtobj.strftime(formatStr) return dtstr[:-2] + dtstr[-2:].lower() +def secondsToHumanTime(nSec): + strPieces = [] + floatSec = float(nSec) + if floatSec < 0.9*MINUTE: + strPieces = [floatSec, 'second'] + elif floatSec < 0.9*HOUR: + strPieces = [floatSec/MINUTE, 'minute'] + elif floatSec < 0.9*DAY: + strPieces = [floatSec/HOUR, 'hour'] + elif floatSec < 0.9*WEEK: + strPieces = [floatSec/DAY, 'day'] + elif floatSec < 0.9*MONTH: + strPieces = [floatSec/WEEK, 'week'] + else: + strPieces = [floatSec/MONTH, 'month'] + + if strPieces[0]<1.25: + return '1 '+strPieces[1] + elif strPieces[0]<=1.75: + return '1.5 '+strPieces[1]+'s' + else: + return '%d %ss' % (int(strPieces[0]+0.5), strPieces[1]) + ##### HEXSTR/VARINT ##### def packVarInt(n): diff --git a/img/armory_logo_green_h72.png b/img/armory_logo_green_h72.png new file mode 100644 index 000000000..1dbf62407 Binary files /dev/null and b/img/armory_logo_green_h72.png differ diff --git a/qtdialogs.py b/qtdialogs.py index ba92786db..3c4598608 100755 --- a/qtdialogs.py +++ b/qtdialogs.py @@ -4708,6 +4708,15 @@ def signTx(self): def broadTx(self): + if not self.main.internetAvail: + QMessageBox.warning(self, 'No Internet!', \ + 'You do not currently have a connection to the Bitcoin network. ' + 'If this does not seem correct, verify your internet connection ' + 'and restart Armory!', QMessageBox.Ok) + return + + + try: finalTx = self.txdpObj.prepareFinalTx() except: