Beispiel #1
0
class main(QDialog):
    #托盘
    def __init__(self):
        super().__init__()
        self.loadMenu()
        self.initUI()

    def loadMenu(self):
        menuItems = []
        menuItems.append({"text": "启动", "icon": "./icon/launch.png", "event": self.show, "hot": "D"})
        menuItems.append({"text": "退出", "icon": "./icon/car.png", "event": self.close, "hot": "Q"})
        self.trayIconMenu = QMenu(self)
        for i in menuItems:
             tmp = QAction(QIcon(i["icon"]), i["text"],self, triggered=i["event"])
             tmp.setShortcut(self.tr(i["hot"]))
             self.trayIconMenu.addAction(tmp)

    def initUI(self):
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setIcon(QIcon("./icon/car.png"))
        self.trayIcon.setContextMenu(self.trayIconMenu)
        self.trayIcon.show()
        self.setWindowIcon(QIcon("./icon/car.png"))
        self.setGeometry(300, 300, 180, 300)
        self.setWindowTitle('窗体标题')
    def closeEvent(self, event):
        if self.trayIcon.isVisible():
            self.trayIcon.hide()
Beispiel #2
0
class MainWindow(QMainWindow):
    def __init__(self, app):
        QMainWindow.__init__(self)

        # Config app icon
        self.app_icon = QtGui.QIcon("assets/icon.png")
        self.setWindowIcon(self.app_icon)

        self.tray_icon = QSystemTrayIcon(self.app_icon, self)
        self.tray_icon.activated.connect(self.tray_icon_event)
        menu = QMenu(self)
        quit_action = menu.addAction("Fechar aplicação")
        quit_action.triggered.connect(app.quit)
        tray_menu = QMenu()
        tray_menu.addAction(quit_action)
        self.tray_icon.setContextMenu(tray_menu)
        self.tray_icon.show()

    def tray_icon_event(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            if not self.isVisible():
                self.show()

    def hide_window_and_tray(self):
        if self.tray_icon.isVisible():
            self.tray_icon.hide()
        if self.isVisible():
            self.hide()

    # When user clicks on window quit button
    def closeEvent(self, event):
        event.ignore()
        self.hide()
        self.tray_icon.showMessage("File upload", "Aplicação foi minimizada", QSystemTrayIcon.Information, 1000)
Beispiel #3
0
class Main(QDialog):
    def __init__(self):
        super().__init__()
        self.loadMenu()
        self.initUI()

    def loadMenu(self):
        menuItems = []  # 菜单列表
        menuItems.append({
            "text": "启动",
            "icon": "./icons/set.png",
            "event": self.show,
            "hot": "D"
        })
        menuItems.append({
            "text": "退出",
            "icon": "./icons/close.png",
            "event": self.close,
            "hot": "Q"
        })
        self.trayIconMenu = QMenu(self)  # 创建菜单
        #遍历绑定 显示的文字、图标、热键和点击事件
        #热键可能是无效的 我这里只是为了显示效果而已
        for i in menuItems:
            tmp = QAction(QIcon(i["icon"]),
                          i["text"],
                          self,
                          triggered=i["event"])
            tmp.setShortcut(self.tr(i["hot"]))
            self.trayIconMenu.addAction(tmp)

    def initUI(self):
        self.trayIcon = QSystemTrayIcon(self)  # <===创建通知栏托盘图标
        self.trayIcon.setIcon(QIcon("./joyrun/request/pic.ico"))  #<===设置托盘图标

        self.trayIcon.setContextMenu(self.trayIconMenu)  #<===创建右键连接菜单
        self.trayIcon.show()  #<====显示托盘

        self.setWindowIcon(QIcon("./joyrun/request/pic.ico"))  #<===设置窗体图标
        self.setGeometry(300, 300, 180, 300)  # <===设置窗体打开位置与宽高
        self.setWindowTitle('窗体标题')

        self.show()  #<====显示窗体
        # self.hide()#<====隐藏窗体
        # 默认不显示窗体

    # 重写窗体关闭事件,让其点击关闭时隐藏
    def closeEvent(self, event):
        if self.trayIcon.isVisible():
            self.trayIcon.hide()
Beispiel #4
0
class main(QDialog):
	def __init__(self):
		super().__init__()
		self.trayIcon = QSystemTrayIcon(self)  # <===创建通知栏托盘图标
		self.trayIconMenu = QMenu(self)  # 创建菜单
		self.loadMenu()
		self.initUI()

	# self.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint)
	# self.tray.activated.connect(self.TuoPanEvent) #设置托盘点击事件处理函数
	def loadMenu(self):
		menuItems = [{"text": "启动", "icon": "icons/set.png", "event": self.show, "hot": "D"},
					 {"text": "退出", "icon": "icons/switch.png", "event": self.close, "hot": "Q"}]  # 菜单列表
		# 遍历绑定 显示的文字、图标、热键和点击事件
		# 热键可能是无效的 我这里只是为了显示效果而已
		for i in menuItems:
			tmp = QAction(QIcon(i["icon"]), i["text"], self, triggered=i["event"])
			tmp.setShortcut(self.tr(i["hot"]))
			self.trayIconMenu.addAction(tmp)

	def initUI(self):
		self.trayIcon.setIcon(QIcon("icons/alert.png"))  # <===设置托盘图标
		self.trayIcon.setContextMenu(self.trayIconMenu)  # <===创建右键连接菜单
		self.trayIcon.show()  # <====显示托盘
		# self.trayIcon.setToolTip('aa')
		self.setWindowIcon(QIcon("icons/alert.png"))  # <===设置窗体图标
		self.setGeometry(900, 300, 180, 300)  # <===设置窗体打开位置与宽高
		self.setWindowTitle('订单列表')

	# self.show()  # <====显示窗体

	# self.hide()#<====隐藏窗体
	# 默认不显示窗体

	def close(self):
		sys.exit(0)

	# 重写窗体关闭事件,让其点击关闭时隐藏
	def closeEvent(self, event):
		if self.trayIcon.isVisible():
			self.hide()
			event.ignore()
		else:
			event.accept()
Beispiel #5
0
class DlgMain(QDialog):
    def addSystemTray(self):
        minimizeAction = QAction("Mi&nimize", self, triggered=self.hide)
        maximizeAction = QAction("Ma&ximize",
                                 self,
                                 triggered=self.showMaximized)
        restoreAction = QAction("&Restore", self, triggered=self.showNormal)
        quitAction = QAction("&Quit", self, triggered=self.close)
        self.trayIconMenu = QMenu(self)
        self.trayIconMenu.addAction(minimizeAction)
        self.trayIconMenu.addAction(maximizeAction)
        self.trayIconMenu.addAction(restoreAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(quitAction)
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setIcon(QIcon("skin/icons/logo.png"))
        self.setWindowIcon(QIcon("skin/icons/logo.png"))
        self.trayIcon.setContextMenu(self.trayIconMenu)
        self.trayIcon.show()
        sys.exit(self.exec_())

    def closeEvent(self, event):
        if self.trayIcon.isVisible():
            self.trayIcon.hide()
Beispiel #6
0
class bridgePanel(QMainWindow, QObject):
    start = pyqtSignal()
    stop = pyqtSignal()

    def __init__(self, app):
        super().__init__()
        self.bridgetreasureChest = bridgetreasureChest.bridgetreasureChest()
        self.app = app
        self.translate = QCoreApplication.translate
        self.__v2rayshellVersion = "20180511"
        self.__windowTitile = "V2Ray-shell" + " " + self.__v2rayshellVersion
        self.runv2raycore = False
        self.iconStart = QIcon()
        self.iconStop = QIcon()
        self.__iconSize = QSize(32, 32)
        self.iconStart.addPixmap(QPixmap(filePath + "/icons/start.png"),
                                 QIcon.Normal, QIcon.On)
        self.iconStop.addPixmap(QPixmap(filePath + "/icons/stop.png"),
                                QIcon.Disabled, QIcon.On)
        self.currentRowRightClicked = False
        self.v2rayshellTrayIcon = QSystemTrayIcon()
        self.v2rayshellTrayIcon.setIcon(self.iconStart)
        self.v2rayshellTrayIcon.show()

        self.radioButtonGroup = QButtonGroup()

        self.setV2RayshellLanguage()
        self.trytimes = self.bridgetreasureChest.getConnectiontrytimes()
        self.interval = self.bridgetreasureChest.getConnectioninterval()
        self.proxyTryConnect = proxyTryconnect()
        if v2rayshellDebug: self.proxyTryConnect.setresetTime(6, 3)
        else: self.proxyTryConnect.setresetTime(self.interval, self.trytimes)
        self.labelBridge = (self.translate("bridgePanel", "Start/Stop"),
                            self.translate("bridgePanel", "Host Name"),
                            self.translate("bridgePanel", "Config Name"),
                            self.translate("bridgePanel", "Proxy"),
                            self.translate("bridgePanel", "Time Lag"))
        self.checkTrayicon = QTimer()
        self.createBridgePanel()

    def createBridgePanel(self):
        self.setWindowTitle(self.__windowTitile)
        self.setWindowIcon(self.iconStart)
        menubar = self.menuBar()
        self.statusBar()

        self.actionNewV2rayConfigFile = QAction(
            self.translate("bridgePanel", "Add V2Ray-core Config File"), self)
        self.actionNewV2rayConfigFile.setShortcut(QKeySequence.New)
        self.actionNewV2rayConfigFile.setStatusTip(
            self.translate("bridgePanel", "Add V2Ray-core Config File"))

        self.actionSaveV2rayshellConfigFile = QAction(
            self.translate("bridgePanel", "Save V2Ray-shell Config File"),
            self)
        self.actionSaveV2rayshellConfigFile.setShortcut(QKeySequence.Save)
        self.actionSaveV2rayshellConfigFile.setStatusTip(
            self.translate("bridgePanel", "Save V2Ray-shell Config File"))

        self.actionReloadV2rayshellConfigFile = QAction(
            self.translate("bridgePanel", "Open V2Ray-shell Config File"),
            self)
        self.actionReloadV2rayshellConfigFile.setShortcut(QKeySequence.Open)
        self.actionReloadV2rayshellConfigFile.setStatusTip(
            self.translate("bridgePanel", "Open V2Ray-shell Config File"))

        self.actionQuitV2rayshellPanel = QAction(
            self.translate("bridgePanel", "Quit"), self)
        if sys.platform.startswith('win'):
            self.actionQuitV2rayshellPanel.setShortcut("Ctrl+Q")
        else:
            self.actionQuitV2rayshellPanel.setShortcut(QKeySequence.Quit)
        self.actionQuitV2rayshellPanel.setStatusTip(
            self.translate("bridgePanel", "Quit V2Ray-shell"))

        fileMenu = menubar.addMenu(self.translate("bridgePanel", "&File"))
        fileMenu.addAction(self.actionNewV2rayConfigFile)
        fileMenu.addSeparator()
        fileMenu.addAction(self.actionReloadV2rayshellConfigFile)
        fileMenu.addAction(self.actionSaveV2rayshellConfigFile)
        fileMenu.addSeparator()
        fileMenu.addAction(self.actionQuitV2rayshellPanel)

        self.texteditBridge = QTextEdit(self)
        self.texteditBridge.setReadOnly(True)

        self.tableWidgetBridge = QTableWidget()
        self.tableWidgetBridge.setRowCount(0)
        self.tableWidgetBridge.setColumnCount(5)
        self.tableWidgetBridge.setHorizontalHeaderLabels(self.labelBridge)
        self.tableWidgetBridge.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.tableWidgetBridge.setSelectionBehavior(
            QAbstractItemView.SelectRows)
        self.tableWidgetBridge.setEditTriggers(
            QAbstractItemView.NoEditTriggers)
        #self.tableWidgetBridge.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.tableWidgetBridge.setContextMenuPolicy(Qt.CustomContextMenu)

        self.popMenu = popMenu = QMenu(self.tableWidgetBridge)
        self.actionpopMenuAddV2rayConfigFile = QAction(
            self.translate("bridgePanel", "Add V2Ray Config File"), self)
        self.actionpopMenuAddV2rayConfigFile.setShortcut("Ctrl+n")
        self.actionpopMenuEditV2rayConfigFile = QAction(
            self.translate("bridgePanel", "Edit V2Ray Config File"), self)
        self.actionpopMenuProxyCheckTimeLag = QAction(
            self.translate("bridgePanel", "Proxy Time Lag Check..."), self)
        self.actionpopMenuDeleteRow = QAction(
            self.translate("bridgePanel", "Delete"), self)

        popMenu.addAction(self.actionpopMenuAddV2rayConfigFile)
        popMenu.addAction(self.actionpopMenuEditV2rayConfigFile)
        popMenu.addAction(self.actionpopMenuProxyCheckTimeLag)
        popMenu.addAction(self.actionpopMenuDeleteRow)

        self.actionopenV2rayshellPreferencesPanel = QAction(
            self.translate("bridgePanel", "preferences"), self)
        self.actionopenV2rayshellPreferencesPanel.setStatusTip(
            self.translate("bridgePanel", "Setting V2Ray-shell"))

        optionMenu = menubar.addMenu(self.translate("bridgePanel", "&options"))
        optionMenu.addAction(self.actionpopMenuProxyCheckTimeLag)
        optionMenu.addAction(self.actionopenV2rayshellPreferencesPanel)

        helpMenu = menubar.addMenu(self.translate("bridgePanel", "&help"))
        self.actioncheckv2raycoreupdate = QAction(
            self.translate("bridgePanel", "check V2Ray-core update"), self)
        self.actionv2rayshellBugreport = QAction(
            self.translate("bridgePanel", "Bug Report"), self)
        self.actionaboutv2rayshell = QAction(
            self.translate("bridgePanel", "About"), self)

        helpMenu.addAction(self.actioncheckv2raycoreupdate)
        helpMenu.addAction(self.actionv2rayshellBugreport)
        helpMenu.addAction(self.actionaboutv2rayshell)

        toolBar = QToolBar()
        self.actionV2rayStart = QAction(self.translate("bridgePanel", "Start"))
        self.actionV2rayStart.setIcon(self.style().standardIcon(
            getattr(QStyle, "SP_MediaPlay")))
        self.actionV2rayStop = QAction(self.translate("bridgePanel", "Stop"))
        self.actionV2rayStop.setIcon(self.style().standardIcon(
            getattr(QStyle, "SP_MediaStop")))
        toolBar.addAction(self.actionV2rayStart)
        toolBar.addAction(self.actionV2rayStop)
        self.addToolBar(toolBar)

        self.trayIconMenu = QMenu()
        self.v2rayshellTrayIcon.setContextMenu(self.trayIconMenu)

        self.trayIconMenushowhidePanel = QAction(
            self.translate("bridgePanel", "Show/Hide"))
        self.trayIconMenuclosePanel = QAction(
            self.translate("bridgePanel", "Quit"))

        self.trayIconMenu.addAction(self.trayIconMenushowhidePanel)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.trayIconMenuclosePanel)

        self.splitterBridge = QSplitter(Qt.Vertical)
        self.splitterBridge.addWidget(self.tableWidgetBridge)
        self.splitterBridge.addWidget(self.texteditBridge)

        self.setCentralWidget(self.splitterBridge)

        self.createBridgePanelSignals()

        self.onloadV2rayshellConfigFile(init=True)

        self.onv2raycoreStart()

        self.autocheckv2raycoreUpdate()

    def createBridgePanelSignals(self):
        self.actionNewV2rayConfigFile.triggered.connect(
            self.tableWidgetBridgeAddNewV2rayConfigFile)
        self.actionReloadV2rayshellConfigFile.triggered.connect(
            self.onloadV2rayshellConfigFile)
        self.actionSaveV2rayshellConfigFile.triggered.connect(
            self.onsaveV2rayshellConfigFile)
        self.actionopenV2rayshellPreferencesPanel.triggered.connect(
            self.createBridgepreferencesPanel)
        self.actionpopMenuAddV2rayConfigFile.triggered.connect(
            self.tableWidgetBridgeAddNewV2rayConfigFile)
        self.actionpopMenuEditV2rayConfigFile.triggered.connect(
            self.oncreatenauticalChartPanel)
        self.actionpopMenuDeleteRow.triggered.connect(
            self.tableWidgetBridgeDelete)
        self.actionpopMenuProxyCheckTimeLag.triggered.connect(
            self.onproxyserverTimeLagTest)
        self.actioncheckv2raycoreupdate.triggered.connect(
            self.onopenv2rayupdatePanel)
        self.actionv2rayshellBugreport.triggered.connect(self.bugReportPanel)
        self.actionQuitV2rayshellPanel.triggered.connect(self.close)
        self.actionV2rayStart.triggered.connect(self.onv2raycoreStart)
        self.actionV2rayStop.triggered.connect(self.onv2raycoreStop)
        self.actionaboutv2rayshell.triggered.connect(self.about)
        self.radioButtonGroup.buttonClicked.connect(self.onradioButtonClicked)
        self.tableWidgetBridge.cellDoubleClicked.connect(
            self.ontableWidgetBridgecellDoubleClicked)
        self.tableWidgetBridge.customContextMenuRequested.connect(
            self.ontableWidgetBridgeRightClicked)
        self.v2rayshellTrayIcon.activated.connect(self.restorebridgePanel)
        self.trayIconMenushowhidePanel.triggered.connect(
            self.onsystemTrayIconMenushowhidebridgePanel)
        self.trayIconMenuclosePanel.triggered.connect(self.close)
        self.proxyTryConnect.reconnectproxy.connect(self.swapNextConfigFile)
        self.start.connect(self.onupdateinstallFinishedstartNewV2raycore)
        self.stop.connect(self.onv2raycoreStop)
        self.checkTrayicon.timeout.connect(self.checkSystemTrayIconStatus)
        self.checkTrayicon.start(1000 * 60)

    def checkSystemTrayIconStatus(self):
        """
        maybe auto startup will missing trayicon
        """
        if not self.v2rayshellTrayIcon.isVisible():
            self.v2rayshellTrayIcon.show()
        else:
            self.checkTrayicon.disconnect()

    def setV2RayshellLanguage(self):
        self.trans = QTranslator()
        language = self.bridgetreasureChest.getLanguage()
        allLanguages = self.bridgetreasureChest.getAllLanguage()
        if language and allLanguages:
            if language in allLanguages:
                self.trans.load(allLanguages[language])
                self.app.installTranslator(self.trans)

    def autocheckv2raycoreUpdate(self):
        self.bridgeSingal = (self.start, self.stop)
        self.v2rayshellautoUpdate = updatePanel.autoCheckUpdate(
            bridgetreasureChest=self.bridgetreasureChest,
            bridgeSingal=self.bridgeSingal)

    def event(self, event):
        if (event.type() == QEvent.WindowStateChange and self.isMinimized()):
            self.setWindowFlags(self.windowFlags() & ~Qt.Tool)
            self.v2rayshellTrayIcon.show()
            return True
        else:
            return super(bridgePanel, self).event(event)

    def onsystemTrayIconMenushowhidebridgePanel(self):
        if self.isHidden():
            self.showNormal()
        elif self.isVisible():
            self.hide()

    def restorebridgePanel(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            if self.isVisible():
                self.hide()
            elif self.isHidden():
                self.showNormal()

    def close(self):
        super(bridgePanel, self).close()
        self.v2rayshellTrayIcon.hide()
        self.onv2raycoreStop()

    def closeEvent(self, event):
        self.close()
        event.accept()
        sys.exit(self.app.exec_())

    def onv2raycoreStop(self):
        if (self.runv2raycore):
            self.runv2raycore.stop.emit()
        try:
            # force stop checking proxy time lag
            del self.autoCheckTimer
        except Exception:
            pass

    def onupdateinstallFinishedstartNewV2raycore(self):
        self.onloadV2rayshellConfigFile(init=True)
        self.onv2raycoreStart()

    def onv2raycoreStart(self):
        currentActiveRow = False
        rowCount = self.tableWidgetBridge.rowCount()
        for i in range(rowCount):
            currentActiveRow = self.tableWidgetBridge.cellWidget(i, 0)
            if currentActiveRow.isChecked():
                self.texteditBridge.clear()
                option = self.tableWidgetBridge.item(i, 2)
                if option:
                    option = '-config="{}" -format=json'.format(option.text())
                else:
                    option = ""
                filePath = self.bridgetreasureChest.getV2raycoreFilePath()
                if (not filePath):
                    filePath = "v2ray"
                self.runv2raycore = runV2raycore.runV2raycore(
                    outputTextEdit=self.texteditBridge,
                    v2rayPath=filePath,
                    v2rayOption=option,
                    bridgetreasureChest=self.bridgetreasureChest)

                self.runv2raycore.start.emit()
                self.autocheckProxy(i)
                break
            else:
                del currentActiveRow

    def autocheckProxy(self, row):
        # TODO
        """
        Frequent access to the server may cause suspicion of DDOS attacks, 
        which may put the VPS server at risk.
        """
        enableAutoCheck = self.bridgetreasureChest.getConnectionEnable()

        if (enableAutoCheck):
            self.proxyStatus = proxyTest.proxyStatus()
            self.autoCheckTimer = QTimer()
            invervalTime = self.bridgetreasureChest.getConnectioninterval()
            timeout = self.bridgetreasureChest.getConnectiontimeout()
            proxyAddress = self.getProxyAddressFromTableWidget(row)

            if proxyAddress:
                self.autoCheckTimer.timeout.connect(
                    lambda: self.startCheckProxy(timeout=timeout,
                                                 proxyAddress=proxyAddress,
                                                 row=row,
                                                 proxyStatus=self.proxyStatus))

                self.bridgetreasureChest.setProxy(proxyAddress)

                if v2rayshellDebug: self.autoCheckTimer.start(6000)
                else: self.autoCheckTimer.start(1000 * invervalTime)

                self.autoCheckTimer.singleShot(
                    100,
                    lambda: self.startCheckProxy(timeout=timeout,
                                                 proxyAddress=proxyAddress,
                                                 row=row,
                                                 proxyStatus=self.proxyStatus))

    def setTableWidgetTimelag(self, row, proxyStatus):
        newlabelTimelag = self.setlabelTimeLagColor(proxyStatus)
        oldlabelTimelag = self.tableWidgetBridge.cellWidget(row, 4)
        del oldlabelTimelag
        self.tableWidgetBridge.setCellWidget(row, 4, newlabelTimelag)
        self.tableWidgetBridge.resizeColumnsToContents()

    def startCheckProxy(self, timeout, proxyAddress, row, proxyStatus):
        if (proxyAddress):
            proxyStatus.clear()
            proxyStatus.signal.connect(
                lambda: self.setTableWidgetTimelag(row, proxyStatus))

            self.proxy = proxyTest.proxyTest(proxyprotocol=proxyAddress[0],
                                             proxyhostname=proxyAddress[1],
                                             proxyhostport=int(
                                                 proxyAddress[2]),
                                             getproxyStatus=proxyStatus,
                                             timeout=int(timeout))

    def setlabelTimeLagColor(self, proxyStatus=False):
        labelTimeLag = QLabel()
        if (proxyStatus and not proxyStatus.getProxyError()):
            labelFont = QFont()
            labelFont.setPointSize(12)
            labelFont.setBold(True)
            labelTimeLag.setFont(labelFont)
            forestGreen = "QLabel {color: rgb(34, 139, 34)}"
            darkOrange = "QLabel {color: rgb(255, 140, 0)}"
            red = "QLabel {color: rgb(194,24,7)}"

            if (proxyStatus.getElapsedTime() < 260):
                labelTimeLag.setStyleSheet(forestGreen)
            elif (proxyStatus.getElapsedTime() > 420):
                labelTimeLag.setStyleSheet(red)
            else:
                labelTimeLag.setStyleSheet(darkOrange)
            labelTimeLag.setText("{} ms".format(
                str(proxyStatus.getElapsedTime())))

            return labelTimeLag

        elif (proxyStatus and proxyStatus.getProxyError()):
            labelTimeLag.setText("{}:{}".format(
                proxyStatus.getProxyErrorString(),
                proxyStatus.getProxyErrorCode()))

            self.proxyTryConnect.trytimesDecrease()
            return labelTimeLag

    def swapNextConfigFile(self):
        self.onv2raycoreStop()
        try:
            self.trytimes = self.bridgetreasureChest.getConnectiontrytimes()
            self.interval = self.bridgetreasureChest.getConnectioninterval()
            self.proxyTryConnect.stopperiodicCheckProxyStatus()
            if v2rayshellDebug: self.proxyTryConnect.setresetTime(6, 3)
            else:
                self.proxyTryConnect.setresetTime(self.interval, self.trytimes)
        except Exception:
            self.proxyTryConnect.setresetTime(60, 3)

        if (self.bridgetreasureChest.connectionisSwitch()):
            # swap next row's configFile
            buttons = self.radioButtonGroup.buttons()
            buttonsNumber = len(buttons)
            activeRow = False
            for i in range(buttonsNumber):
                if buttons[i].isChecked():
                    buttons[i].setChecked(False)
                    if i == buttonsNumber - 1:
                        buttons[0].setChecked(True)
                        activeRow = 0
                        break
                    else:
                        buttons[i + 1].setChecked(True)
                        activeRow = i + 1
                    break

            # change the row icons
            for i in range(buttonsNumber):
                widget = self.tableWidgetBridge.cellWidget(i, 0)
                if (widget):
                    widget.setIcon(self.iconStop)
                    widget.setIconSize(self.__iconSize)
                    if (widget.isChecked()):
                        pass
            widget = self.tableWidgetBridge.cellWidget(activeRow, 0)
            if widget:
                widget.setIcon(self.iconStart)
                widget.setIconSize(self.__iconSize)

        self.onv2raycoreStart()

    def onopenv2rayupdatePanel(self):
        currentActiveRow = False
        rowCount = self.tableWidgetBridge.rowCount()
        currentRow = False
        for i in range(rowCount):
            currentActiveRow = self.tableWidgetBridge.cellWidget(i, 0)
            if currentActiveRow.isChecked():
                currentRow = i
                break

        if (currentActiveRow and currentActiveRow.isChecked()):
            proxy = self.tableWidgetBridge.item(currentRow, 3)
            proxy = proxy.text().split(":")
            protocol = QNetworkProxy.Socks5Proxy
            if (proxy[0] == "socks"):
                protocol = QNetworkProxy.Socks5Proxy
            elif (proxy[0] == "http"):
                protocol = QNetworkProxy.HttpProxy
            hostName = proxy[1]
            hostPort = int(proxy[2])

            v2rayAPI = updatePanel.v2rayAPI()
            self.createupdatePanel = updatePanel.v2rayUpdatePanel(
                v2rayapi=v2rayAPI,
                protocol=protocol,
                proxyhostName=hostName,
                port=hostPort,
                bridgetreasureChest=self.bridgetreasureChest)
            self.createupdatePanel.createPanel()
            self.createupdatePanel.setAttribute(Qt.WA_DeleteOnClose)
            self.createupdatePanel.setWindowIcon(self.iconStart)
            self.createupdatePanel.setWindowTitle(
                self.translate("bridgePanel", "Check V2Ray-core update"))
            self.createupdatePanel.resize(QSize(1024, 320))
            self.createupdatePanel.move(
                QApplication.desktop().screen().rect().center() -
                self.createupdatePanel.rect().center())
            self.createupdatePanel.show()
            self.createupdatePanel.exec_()
        else:
            self.noPoxyServerRunning()

    def ontableWidgetBridgeRightClicked(self, pos):
        index = self.tableWidgetBridge.indexAt(pos)
        clickedRow.rightClickedRow = index.row()
        clickedRow.mousePos = QCursor().pos()
        self.popMenu.move(QCursor().pos())
        self.popMenu.show()

    def ontableWidgetBridgecellDoubleClicked(self, row, column):
        if (column == 1):
            hostName, ok = QInputDialog.getText(
                self, self.translate("bridgePanel", 'Host Name'),
                self.translate("bridgePanel", 'Enter Host Name:'))
            if (ok):
                self.tableWidgetBridge.setItem(row, column,
                                               QTableWidgetItem(str(hostName)))
                self.tableWidgetBridge.resizeColumnsToContents()
        elif (column == 2):
            fileNames = self.onopenV2rayConfigJSONFile()
            if (fileNames):
                for fileName in fileNames:
                    self.tableWidgetBridge.setItem(
                        row, column, QTableWidgetItem(str(fileName)))
                    self.tableWidgetBridge.resizeColumnsToContents()
        elif (column == 3):
            self.onproxyserverTimeLagTest()
        elif (column == 4):
            self.onproxyserverTimeLagTest()

    def getProxyAddressFromTableWidget(self, row):
        proxy = self.tableWidgetBridge.item(row, 3)
        try:
            proxy = proxy.text().split(":")
        except Exception:
            return False

        if (proxy[0] == "socks"):
            proxy[0] = QNetworkProxy.Socks5Proxy
        elif (proxy[0] == "http"):
            proxy[0] = QNetworkProxy.HttpProxy

        if len(proxy) < 3: return False
        else: return proxy

    def onproxyserverTimeLagTest(self):
        proxyStatus = proxyTest.proxyStatus()
        """
        right clicked mouse button pop a menu check proxy
        """
        currentActiveRow = False
        rowCount = self.tableWidgetBridge.rowCount()
        currentRow = False
        for i in range(rowCount):
            currentActiveRow = self.tableWidgetBridge.cellWidget(i, 0)
            if currentActiveRow.isChecked():
                currentRow = i
                break
        if (currentActiveRow and currentActiveRow.isChecked()):
            proxy = self.getProxyAddressFromTableWidget(currentRow)
            if not proxy: return
            protocol = proxy[0]
            hostName = proxy[1]
            hostPort = int(proxy[2])

            proxy = proxyTest.proxyTestPanel(proxyhostname=hostName,
                                             proxyhostport=hostPort,
                                             proxyprotocol=protocol,
                                             getproxyStatus=proxyStatus)
            proxy.createproxyTestPanel()
            proxy.setAttribute(Qt.WA_DeleteOnClose)
            proxy.setWindowTitle(
                self.translate("bridgePanel", "Proxy Time Lag Check"))
            proxy.setWindowIcon(self.iconStart)
            proxy.resize(QSize(600, 480))
            proxy.move(QApplication.desktop().screen().rect().center() -
                       proxy.rect().center())
            proxy.show()
            proxy.exec_()
        else:
            self.noPoxyServerRunning()

    def noPoxyServerRunning(self):
        warningPanel = QDialog()
        warningPanel.setAttribute(Qt.WA_DeleteOnClose)
        warningPanel.setWindowTitle(self.translate("bridgePanel",
                                                   "Warnnig..."))
        warningPanel.setWindowIcon(self.iconStop)
        labelMsg = QLabel(
            self.translate(
                "bridgePanel",
                "There no any server is running, \n[File]->[Add V2Ray-core Config File] (Ctrl+n) add a config.json."
            ))
        vbox = QVBoxLayout()
        vbox.addWidget(labelMsg)
        warningPanel.setLayout(vbox)
        warningPanel.move(QApplication.desktop().screen().rect().center() -
                          warningPanel.rect().center())
        warningPanel.open()
        warningPanel.exec_()

    def getProxyAddressFromJSONFile(self, filePath):
        from bridgehouse.editMap.port import treasureChest, openV2rayJSONFile
        tempTreasureChest = treasureChest.treasureChest()
        openV2rayJSONFile.openV2rayJSONFile(
            filePath, tempTreasureChest, disableLog=True).initboundJSONData()
        inbound = tempTreasureChest.getInbound()
        if (inbound):
            try:
                protocol = inbound["protocol"]
                ipAddress = inbound["listen"]
                port = inbound["port"]
                if (protocol == "socks" or protocol == "http"):
                    return "{}:{}:{}".format(protocol, ipAddress, port)
                else:
                    return False
            except Exception:
                return False
        else:
            return False

    def onradioButtonClicked(self, e):
        rowCount = self.tableWidgetBridge.rowCount()
        # radioButtonClickedRow = 0
        for i in range(rowCount):
            widget = self.tableWidgetBridge.cellWidget(i, 0)
            if (widget):
                widget.setIcon(self.iconStop)
                widget.setIconSize(self.__iconSize)
                if (widget.isChecked()):
                    # radioButtonClickedRow = i
                    pass
        e.setIcon(self.iconStart)
        e.setIconSize(self.__iconSize)

    def onloadV2rayshellConfigFile(self, init=False):
        """
        when the script first start, and auto load v2ray-shell config file.
        """
        if init:
            self.settingv2rayshelltableWidget()
        else:

            def openV2rayshellConfigFile():
                options = QFileDialog.Options()
                filePath, _ = QFileDialog.getOpenFileName(
                    self,
                    self.translate("bridgePanel",
                                   "Open V2Ray-sehll Config File"),
                    "",
                    "V2Ray-shell config file (*.v2rayshell)",
                    options=options)
                if (filePath):
                    self.bridgetreasureChest.clear()
                    self.tableWidgetBridge.setRowCount(0)
                    self.bridgetreasureChest.initbridgeJSONData(
                        v2rayshellConfigFileName=filePath)
                    self.settingv2rayshelltableWidget()

            openV2rayshellConfigFile()

    def onopenV2rayConfigJSONFile(self):
        """
        open a new v2ray config file to tabelWidget
        """
        options = QFileDialog.Options()
        filePaths, _ = QFileDialog.getOpenFileNames(
            self,
            self.translate("bridgePanel", "Open V2Ray-core Config File"),
            "",
            """
                                                  V2Ray config file (*.json);;
                                                  All File (*);;
                                                  """,
            options=options)

        if (filePaths):
            return filePaths
        else:
            return False

    def createBridgepreferencesPanel(self):
        self.createpreferencesPanel = bridgePreference.bridgepreferencesPanel(
            self.bridgetreasureChest)
        self.createpreferencesPanel.setAttribute(Qt.WA_DeleteOnClose)
        self.createpreferencesPanel.createpreferencesPanel()
        self.createpreferencesPanel.setWindowIcon(self.iconStart)
        self.createpreferencesPanel.move(
            QApplication.desktop().screen().rect().center() -
            self.createpreferencesPanel.rect().center())
        self.createpreferencesPanel.open()
        self.createpreferencesPanel.exec_()

    def settingv2rayshelltableWidget(self):
        v2rayConfigFiles = self.bridgetreasureChest.getV2raycoreconfigFiles()
        if not v2rayConfigFiles: return
        v2rayConfigFilesNumber = len(v2rayConfigFiles)
        if (v2rayConfigFilesNumber):
            self.tableWidgetBridge.setRowCount(0)
            for i in range(v2rayConfigFilesNumber):
                try:
                    enable = bool(v2rayConfigFiles[i]["enable"])
                    hostName = str(v2rayConfigFiles[i]["hostName"])
                    configFileName = str(v2rayConfigFiles[i]["configFileName"])
                except Exception:
                    pass

                radioButtonStopStart = QRadioButton(self)
                radioButtonStopStart.setIcon(
                    self.iconStop if not enable else self.iconStart)
                radioButtonStopStart.setChecked(True if enable else False)
                radioButtonStopStart.setIconSize(self.__iconSize)
                self.radioButtonGroup.addButton(radioButtonStopStart)
                self.tableWidgetBridge.setRowCount(i + 1)
                self.tableWidgetBridge.setCellWidget(i, 0,
                                                     radioButtonStopStart)
                self.tableWidgetBridge.setItem(i, 1,
                                               QTableWidgetItem(hostName))
                self.tableWidgetBridge.setItem(
                    i, 2, QTableWidgetItem(configFileName))
                self.tableWidgetBridge.setItem(
                    i, 3,
                    QTableWidgetItem(
                        self.getProxyAddressFromJSONFile(configFileName)))
                self.tableWidgetBridge.resizeColumnsToContents()
                #self.tableWidgetBridge.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    def onsaveV2rayshellConfigFile(self):
        self.bridgetreasureChest.clearconfigFiles()
        rowCount = self.tableWidgetBridge.rowCount()
        for i in range(rowCount):
            enable = self.tableWidgetBridge.cellWidget(i, 0)
            if enable and enable.isChecked():
                enable = True
            else:
                enable = False

            hostName = self.tableWidgetBridge.item(i, 1)
            if hostName:
                hostName = hostName.text()
            else:
                hostName = ""

            config = self.tableWidgetBridge.item(i, 2)
            if config:
                config = config.text()
            else:
                config = ""
            self.bridgetreasureChest.setV2raycoreconfigFiles(
                enable, hostName, configFileName=config)
        self.bridgetreasureChest.save.emit()

    def oncreatenauticalChartPanel(self):
        v2rayConfigFileName = self.tableWidgetBridge.item(
            clickedRow.rightClickedRow, 2)
        if (v2rayConfigFileName):
            nc = nauticalChartPanel.nauticalChartPanel(
                v2rayConfigFileName.text())
            nc.setAttribute(Qt.WA_DeleteOnClose)
            nc.createPanel()
            nc.setWindowTitle(
                self.translate("bridgePanel", "V2Ray config file edit"))
            nc.setWindowIcon(self.iconStart)
            nc.setGeometry(0, 0, 1024, 768)
            # move widget to center
            nc.move(QApplication.desktop().screen().rect().center() -
                    nc.rect().center())
            nc.show()
            nc.exec_()

    def tableWidgetBridgeAddNewV2rayConfigFile(self):
        configFileNames = self.onopenV2rayConfigJSONFile()
        if (configFileNames):
            for configFileName in configFileNames:
                rowCount = self.tableWidgetBridge.rowCount()
                radioButtonStopStart = QRadioButton(self)
                radioButtonStopStart.setIcon(self.iconStop)
                radioButtonStopStart.setIconSize(self.__iconSize)
                self.radioButtonGroup.addButton(radioButtonStopStart)

                self.tableWidgetBridge.setRowCount(rowCount + 1)
                self.tableWidgetBridge.setCellWidget(rowCount, 0,
                                                     radioButtonStopStart)
                self.tableWidgetBridge.setItem(rowCount, 1,
                                               QTableWidgetItem(""))
                self.tableWidgetBridge.setItem(
                    rowCount, 2, QTableWidgetItem(configFileName))
                self.tableWidgetBridge.setItem(
                    rowCount, 3,
                    QTableWidgetItem(
                        self.getProxyAddressFromJSONFile(configFileName)))
                self.tableWidgetBridge.resizeColumnsToContents()
        else:
            pass

    def tableWidgetBridgeDelete(self):
        self.tableWidgetBridge.removeRow(clickedRow.rightClickedRow)

    def validateV2rayJSONFile(self, JSONData):
        """
        simply validate a V2Ray json file.
        """
        try:
            JSONData["inbound"]
            JSONData["outbound"]
        except KeyError:
            return False
        else:
            return True

    def about(self):
        NineteenEightySeven = QLabel(
            self.translate(
                "bridgePanel",
                """Across the Great Wall, we can reach every corner in the world."""
            ))  ### Crossing the Great Wall to Join the World
        Timeless = QLabel(
            self.translate(
                "bridgePanel",
                """You weren't thinking about that when you were creating it.\nBecause if you did? You never would have gone through with it."""
            ))
        DwayneRichardHipp = QLabel(
            self.translate(
                "bridgePanel",
                """May you do good and not evil.\nMay you find forgiveness for yourself and forgive others.\nMay you share freely, never taking more than you give."""
            ))
        vbox = QVBoxLayout()
        vbox.addWidget(NineteenEightySeven)
        vbox.addWidget(Timeless)
        vbox.addWidget(DwayneRichardHipp)

        dialogAbout = QDialog()
        dialogAbout.setAttribute(Qt.WA_DeleteOnClose)
        dialogAbout.setWindowTitle(
            self.translate("bridgePanel", "About V2Ray-shell"))
        dialogAbout.setWindowIcon(self.iconStart)
        dialogAbout.move(QApplication.desktop().screen().rect().center() -
                         dialogAbout.rect().center())
        dialogAbout.setLayout(vbox)
        dialogAbout.open()
        dialogAbout.exec_()

    def bugReportPanel(self):
        self.bugReport = bugReport.bugReport()
        self.bugReport.setAttribute(Qt.WA_DeleteOnClose)
        self.bugReport.setWindowTitle(
            self.translate("bridgePanel", "Bug Report"))
        self.bugReport.setWindowIcon(self.iconStart)
        self.bugReport.createPanel()
        self.bugReport.show()
        self.bugReport.setGeometry(250, 150, 1024, 768)
Beispiel #7
0
class mainInterface(QWidget):

    # 定义信号
    processFinished = pyqtSignal(dict)

    def __init__(self):
        """
        初始化
        :return: null
        """
        # 超类初始化
        super().__init__()

        # UI初始化
        self.ui = Ui_mainWidget()
        self.ui.setupUi(self)
        self.grabKeyboard()
        self.setMouseTracking(True)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setWindowIcon(QIcon('OCR.ico'))

        # 初始化相机
        self.camera = QCamera()
        self.imageCapture = QCameraImageCapture(self.camera)
        self.viewsetting = QCameraViewfinderSettings()
        self.initimplement()

        # 初始化标题栏
        self.initTitleBar()

        # 初始化系统托盘
        self.tray = QSystemTrayIcon()
        self.tray.setIcon(QIcon('OCR.ico'))
        self.initTray()

        # OCR识别部分
        self.OCR = ocr()
        self.OCR.setappid('1257206643')
        self.OCR.setsecretid('AKIDFTddWEg9Ncsz0sE7oOpBNOExdDdeCUJ3')
        self.OCR.setsecretkey('FQitsgUND8yfrZK0RrBMOJB5tWhCm5Ol')

        # 初始化登录部分
        self.logWidget = QWidget()
        self.logui = Ui_Form()
        self.logui.setupUi(self.logWidget)
        self.logWidget.setWindowFlags(Qt.FramelessWindowHint)
        self.logWidget.setWindowModality(Qt.ApplicationModal)
        self.logui.close_btn.clicked.connect(self.logWidget.close)

        # 初始化变量
        self.mousePressd = False
        self.mousePoint = None
        self.result = {}
        self.isFirst = False
        self.ocrType = ocrType.ocr_general  # 默认为印刷体识别

        # 初始化字定义信号连接
        self.processFinished.connect(self.updateOCRInfo)
        self.ui.btn_login.clicked.connect(self.logWidget.show)
        self.ui.comboBox_choose.currentIndexChanged.connect(self.changeocrType)

    def initTitleBar(self):
        """
        初始化标题栏
        :return: null
        """
        self.ui.frame.setStyleSheet(
            "QFrame#frame{background-color:rgb(244, 76, 76);}")
        self.ui.label_logo.setStyleSheet(
            "QLabel{border-image:url(./image/ocr.png);}")
        self.ui.label_title.setStyleSheet(
            "QLabel{border-image:url(./image/iOCR.png);}")
        self.ui.comboBox_choose.setStyleSheet(
            "QComboBox {border-radius:15px;border: 2px solid #4AFFF4;font-family:'楷体';font-size:20px;}"
            "QComboBox QAbstractItemView::item{height:50px;width:200px;}"
            "QComboBox::down-arrow{image: url(./image/arrow.png);width:25px;height:25px;}"
            "QComboBox::drop-down {subcontrol-origin: padding;subcontrol-position:top right;border:none;margin-right:30px;}"
            "QComboBox::down-arrow:hover{image:url(./image/arrow_hover.png);width:25px;height:25px;}"
            "QComboBox::down-arrow:on {top: 1px;left: 1px;}")
        self.ui.comboBox_choose.insertItem(0, '       印刷体识别')
        self.ui.comboBox_choose.insertItem(1, '       手写体识别')
        self.ui.comboBox_choose.insertItem(2, '       身份证识别')
        self.ui.comboBox_choose.insertItem(3, '       名片识别')
        self.ui.comboBox_choose.insertItem(4, '       银行卡识别')
        self.ui.btn_login.setStyleSheet(
            "QPushButton{border-image:url(./image/default-portrait.png);}")
        self.ui.btn_setting.setStyleSheet(
            "QPushButton{border-image:url(./image/settings.png);}"
            "QPushButton:hover{border-image:url(./image/qcconfig-hover.png);}")
        self.ui.btn_min.setStyleSheet(
            "QPushButton{border-image:url(./image/mini_new.png);}"
            "QPushButton:hover{border-image:url(./image/mini_hover_new.png);}")
        self.ui.btn_close.setStyleSheet(
            "QPushButton{border-image:url(./image/close.png);}"
            "QPushButton:hover{border-image:url(./image/close-hover.png);}")
        self.ui.checkBox_cam.setStyleSheet(
            "QCheckBox{spacing: 5px;font-size: 24px;vertical-align:middle}"
            "QCheckBox::indicator { width: 45px;height: 45px;}"
            "QCheckBox::indicator::unchecked {image: url(./image/close_cam.png);}"
            "QCheckBox::indicator::checked { image: url(./image/open_cam.png);}"
        )
        self.ui.captureBtn.setStyleSheet(
            "QPushButton{border-style: outset;border-width: 2px;border-color: rgb(82,215,100);border-radius: 5px;font-size: 24px;}"
            "QPushButton:pressed{background-color: rgb(176,215,181);border-style: inset;}"
        )

        self.ui.checkBox_cam.setChecked(True)

        self.ui.btn_close.clicked.connect(lambda: qApp.quit())
        self.ui.btn_min.clicked.connect(self.miniToTray)
        self.ui.checkBox_cam.stateChanged.connect(self.camControl)

    def initTray(self):
        """
        初始化系统托盘信息
        :return:
        """
        tray_menu = QMenu()
        restoreAction = QAction('&Show', self)
        quitAction = QAction('&Quit', self)
        tray_menu.addAction(restoreAction)
        tray_menu.addAction(quitAction)
        self.tray.setContextMenu(tray_menu)
        restoreAction.triggered.connect(self.trayActivatedEvent)
        quitAction.triggered.connect(qApp.quit)
        self.tray.activated.connect(self.trayActivatedEvent)

    def initimplement(self):
        """
        初始化实现端口
        :return: ui
        """
        camInfo = QCameraInfo(self.camera)
        if camInfo.defaultCamera().isNull():
            QMessageBox.warning(self, 'Warning', 'No available camera!',
                                QMessageBox.Ok)
            return -1
        else:
            self.ui.caputurePhoto.setText(camInfo.description())
            self.camera.setViewfinder(self.ui.cameraShow)
            self.camera.setCaptureMode(QCamera.CaptureStillImage)
            self.camera.load()
            resolution = self.camera.supportedViewfinderResolutions()
            if len(resolution) != 0:
                if QSize(640, 480) in resolution:
                    self.viewsetting.setResolution(QSize(640, 480))
                elif QSize(640, 360) in resolution:
                    self.viewsetting.setResolution(QSize(640, 360))
                else:
                    self.viewsetting.setResolution(resolution[0])
                self.camera.setViewfinderSettings(self.viewsetting)

            # ------------------------------Note--------------------------------
            # 此种方法利用摄像头准备捕捉图像的状态来进行捕捉图像,readyForCapture
            # 为true时,才进行捕捉图像,详见下面捕捉函数槽函数。这种方法将进行不
            # 停的捕捉,将每次捕捉的相邻图像进行图像相似度判断。当图像相似度低于
            # 阈值时,认定为新图像,才进行OCR识别。否则仅捕捉图像而不进行识别。当
            # 然捕捉图像速度过于太快时,可以用定时器,每隔0.5秒,去检查readyFor
            # Capture状态位,进而有效控制程序资源。
            # 本应用中采用按键捕捉方式,非自动,详见下面按键捕捉事件
            # ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
            # self.imageCapture.readyForCaptureChanged.connect(self.captureimage)

            self.camera.start()

        self.ui.caputurePhoto.setScaledContents(True)

        self.imageCapture.setCaptureDestination(
            QCameraImageCapture.CaptureToBuffer)

        self.imageCapture.imageCaptured.connect(self.displayimage)

        self.ui.captureBtn.clicked.connect(self.openDlg)

    def displayimage(self, num, image):
        """
        显示图形
        :param num: number
        :param image: image
        :return: null
        """
        self.ui.caputurePhoto.setPixmap(QPixmap.fromImage(image))
        self.ui.ocrInfo.setText('识别中......')
        t = threading.Thread(target=self.ocrForImage, args=(image, ))
        t.start()

    # def captureimage(self, state):
    #     """
    #     捕捉图像槽函数
    #     :state: 状态变量
    #     :return: null
    #     """
    #     if state is True:
    #         self.camera.searchAndLock()
    #         self.imageCapture.capture()
    #         self.camera.unlock()

    # def saveimage(self):
    #     """
    #     保存图像槽函数
    #     :return: null
    #     """
    #     pix = QPixmap(self.ui.caputurePhoto.pixmap())
    #     if pix:
    #         pix.save(r'D://1.png', 'PNG')
    #         QMessageBox.information(self, 'Message', 'Capture Successfully', QMessageBox.Ok)

    def ocrForImage(self, image):
        """
        为截取的图片进行ocr识别
        :param image: QImage
        :return: null
        """
        # Note:子线程里不能对ui界面做改动,ui界面修改只能在主线程中修改,下面注释的做法是错误的
        # self.ui.ocrInfo.setText('识别中......')
        byte = QByteArray()
        buffer = QBuffer(byte)
        buffer.open(QIODevice.WriteOnly)
        image.save(buffer, 'PNG')
        if self.ocrType == ocrType.ocr_general:
            self.result = self.OCR.client.general_detect(
                CIBuffers([byte.data()]))
        elif self.ocrType == ocrType.ocr_handwriting:
            self.result = self.OCR.client.handwriting_detect(
                CIBuffers([byte.data()]))
        elif self.ocrType == ocrType.ocr_idcard:
            self.result = self.OCR.client.idcard_detect(
                CIBuffers([byte.data()]), 0)
        elif self.ocrType == ocrType.ocr_namecard:
            self.result = self.OCR.client.namecard_detect(
                CIBuffers([byte.data()]), 0)
        elif self.ocrType == ocrType.ocr_bankcard:
            self.result = self.OCR.client.bankcard_detect(
                CIBuffers([byte.data()]))
        else:
            pass
        self.processFinished.emit(self.result)

    def updateOCRInfo(self, res):
        """
        将ocr识别结果显示在信息框中
        :param res:
        :return:
        """
        if self.ocrType == ocrType.ocr_general or self.ocrType == ocrType.ocr_handwriting:
            if res['code'] == 0 and res['message'] == 'OK':
                self.ui.ocrInfo.setText('OK')
                ocrInfo = []
                for i in range(len(self.result['data']['items'])):
                    ocrInfo.append(
                        self.result['data']['items'][i]['itemstring'])
                self.ui.ocrInfo.setText(''.join(ocrInfo))
            else:
                self.ui.ocrInfo.setText('识别失败!')
        elif self.ocrType == ocrType.ocr_bankcard:
            if res['code'] == 0 and res['message'] == 'OK':
                self.ui.ocrInfo.setText('OK')
                ocrInfo = []
                for i in range(len(self.result['data']['items'])):
                    ocrInfo.append(self.result['data']['items'][i]['item'])
                    ocrInfo.append(':')
                    ocrInfo.append(
                        self.result['data']['items'][i]['itemstring'])
                    ocrInfo.append('\n')
                self.ui.ocrInfo.setText(''.join(ocrInfo))
            else:
                self.ui.ocrInfo.setText('识别失败!')
        elif self.ocrType == ocrType.ocr_idcard:
            if res['result_list'][0]['code'] == 0 and res['result_list'][0][
                    'message'] == 'OK':
                self.ui.ocrInfo.setText('OK')
                ocrInfo = []
                ocrInfo_keys = list(
                    self.result['result_list'][0]['data'].keys())
                ocrInfo_values = list(
                    self.result['result_list'][0]['data'].values())
                for i in range(
                        len(self.result['result_list'][0]['data']) // 2):
                    ocrInfo.append(ocrInfo_keys[i])
                    ocrInfo.append(':')
                    ocrInfo.append(ocrInfo_values[i])
                    ocrInfo.append('\n')
                self.ui.ocrInfo.setText(''.join(ocrInfo))
            else:
                self.ui.ocrInfo.setText('识别失败!')
        elif self.ocrType == ocrType.ocr_namecard:
            if res['result_list'][0]['code'] == 0 and res['result_list'][0][
                    'message'] == 'OK':
                self.ui.ocrInfo.setText('OK')
                ocrInfo = []
                for i in range(len(self.result['result_list'][0]['data'])):
                    ocrInfo.append(
                        self.result['result_list'][0]['data'][i]['item'])
                    ocrInfo.append(':')
                    ocrInfo.append(
                        self.result['result_list'][0]['data'][i]['value'])
                    ocrInfo.append('\n')
                self.ui.ocrInfo.setText(''.join(ocrInfo))
            else:
                self.ui.ocrInfo.setText('识别失败!')
        else:
            pass

    def camControl(self, state):
        """
        槽函数
        控制相机开关
        :param state: checkbox开关状态
        :return:null
        """
        if state == Qt.Unchecked:
            self.ui.cameraShow.setUpdatesEnabled(False)
        elif state == Qt.Checked:
            self.ui.cameraShow.setUpdatesEnabled(True)
        else:
            return -1

    def miniToTray(self):
        """
        槽函数
        最小化到系统托盘
        :return:null
        """
        if not self.tray.isVisible():
            self.tray.show()
        if self.tray.isVisible():
            if self.isFirst is False:
                QMessageBox.information(
                    self, "Systray", "The program will keep running in the "
                    "system tray. To terminate the program, "
                    "choose <b>Quit</b> in the context menu "
                    "of the system tray entry.")
                self.isFirst = True
            self.hide()

    def trayActivatedEvent(self, reason):
        """
        槽函数
        响应点击托盘图标
        :param reason: 响应原因
        :return: null
        """
        if reason == QSystemTrayIcon.Context:
            pass
        else:
            self.tray.hide()
            self.show()

    def openDlg(self):
        """
        槽函数
        打开对话框选取文件
        :return:文件名
        """
        filename, filetype = QFileDialog.getOpenFileName(
            self, '选取图片', path.expanduser('~'),
            "Image Files (*.png *.jpg *.bmp)")
        if filename:
            if QFile(filename).size() >= 6291456:
                QMessageBox.information(self, '打开图片',
                                        '选择图片大于6MB大小,暂不支持识别,请重新选择。')
                self.openDlg()
            else:
                self.displayimage(0, QImage(filename))

    def keyPressEvent(self, e):
        """
        槽函数
        键盘按键响应事件
        :param e: 按键事件
        :return: null
        """
        if e.key() == Qt.Key_Space:
            if self.imageCapture.isReadyForCapture():
                self.camera.searchAndLock()
                self.imageCapture.capture()
                self.camera.unlock()

    def mouseMoveEvent(self, e):
        """
        槽函数
        定义鼠标移动事件
        :param e: QMouseEvent
        :return: null
        """
        if (e.buttons() == Qt.LeftButton) and self.mousePressd:
            self.move(e.globalPos() - self.mousePoint)
            e.accept()

    def mousePressEvent(self, e):
        """
        槽函数
        定义鼠标按下事件
        :param e: QMouseEvent
        :return: null
        """
        if e.button() == Qt.LeftButton:
            self.mousePressd = True
            self.mousePoint = e.globalPos() - self.pos()
            e.accept()

    def mouseReleaseEvent(self, e):
        """
        槽函数
        定义鼠标松开事件
        :param e: QMouseEvent
        :return: null
        """
        self.mousePressd = False

    def changeocrType(self, index):
        """
        槽函数
        改变ocr识别类型
        :param index: int
        :return: null
        """
        if index == 0:
            self.ocrType = ocrType.ocr_general
        elif index == 1:
            self.ocrType = ocrType.ocr_handwriting
        elif index == 2:
            self.ocrType = ocrType.ocr_idcard
        elif index == 3:
            self.ocrType = ocrType.ocr_namecard
        elif index == 4:
            self.ocrType = ocrType.ocr_bankcard
        else:
            pass
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        # 定义主界面
        self.setWindowIcon(QIcon('.\\clip.ico'))
        # 主窗口的默认有右键菜单,默认的右键菜单不满足要求,因此采用以下语句停用
        self.setContextMenuPolicy(Qt.NoContextMenu)
        self.setEnabled(True)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setStyleSheet('QMainWindow { background-color: #F0F0F0 }'
                           'QWidget { font-family: \'Microsoft YaHei UI\' }')

        # 桌面控件
        desktop_widget = QApplication.desktop()
        desk_height = desktop_widget.height()
        desk_width = desktop_widget.width()
        self.window_width = 400
        self.window_height = 300
        self.setGeometry(int((desk_width - self.window_width) / 2),
                         int((desk_height - self.window_height) / 2),
                         self.window_width, self.window_height)
        # self.setWindowState(Qt.WindowMaximized)
        self.setMinimumSize(QSize(self.window_width, self.window_height))
        # 获得系统得剪切板
        self.clip_board = QApplication.clipboard()
        # 连接数据库
        self.db_conn = sqlite3.connect('clip_board_database.db')
        self.db_cursor = self.db_conn.cursor()
        # 是否置顶
        self.is_top = False
        # 是否移动
        self.on_move = False
        # 窗口状态
        self.window_status = ''
        # 记录鼠标的世界坐标
        self.mouse_start_point = None
        # 记录窗体的形状数据
        self.window_geo = None
        # 托盘图标
        self.tray_icon = QSystemTrayIcon(QIcon('.\\clip.ico'), self)
        self.tray_icon.setToolTip('自定义粘贴板')
        # 托盘菜单
        self.tray_icon_menu = QMenu(self)
        restore_action = QAction('还原', self)
        restore_action.triggered.connect(self.showNormal)
        quit_action = QAction('退出', self)
        quit_action.triggered.connect(QApplication.quit)
        self.tray_icon.activated.connect(self.restore_win)
        self.tray_icon_menu.addActions([restore_action, quit_action])
        self.tray_icon.setContextMenu(self.tray_icon_menu)
        self.tray_icon.show()

        # 布局,创建子控件
        self.central_widget = QWidget(self)
        self.v_layout_main_window = QVBoxLayout(self.central_widget)
        self.v_layout_main_window.setContentsMargins(0, 0, 0, 0)
        self.v_layout_main_window.setSpacing(0)
        self.widget_title = QWidget(self.central_widget)
        self.horizontalLayout = QHBoxLayout(self.widget_title)
        spacer_item = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacer_item)
        self.horizontalLayout.setSpacing(0)
        self.tool_button_top = QToolButton(self.central_widget)
        self.tool_button_top.setIcon(QIcon('.\\top.ico'))
        self.tool_button_top.setIconSize(QSize(20, 20))
        self.tool_button_top.setStyleSheet(
            'QToolButton { background-color: transparent;'
            'height: 20px; width: 20px; }')
        self.tool_button_top.setFocusPolicy(Qt.NoFocus)
        self.horizontalLayout.addWidget(self.tool_button_top)
        # self.tool_button_back = QToolButton(self.central_widget)
        # self.tool_button_back.setIcon(QIcon('.\\back.ico'))
        # self.tool_button_back.setIconSize(QSize(20, 20))
        # self.tool_button_back.setStyleSheet('QToolButton { background-color: transparent;'
        #                                     'height: 20px; width: 20px; }')
        # self.tool_button_back.setFocusPolicy(Qt.NoFocus)
        # self.horizontalLayout.addWidget(self.tool_button_back)
        self.tool_button_min = QToolButton(self.central_widget)
        self.tool_button_min.setIcon(QIcon('.\\min.ico'))
        self.tool_button_min.setIconSize(QSize(20, 20))
        self.tool_button_min.setStyleSheet(
            'QToolButton { background-color: transparent;'
            'height: 20px; width: 20px; }')
        self.tool_button_min.setFocusPolicy(Qt.NoFocus)
        self.horizontalLayout.addWidget(self.tool_button_min)
        self.tool_button_max = QToolButton(self.central_widget)
        self.tool_button_max.setIcon(QIcon('.\\max.ico'))
        self.tool_button_max.setIconSize(QSize(20, 20))
        self.tool_button_max.setStyleSheet(
            'QToolButton { background-color: transparent;'
            'height: 20px; width: 20px; }')
        self.tool_button_max.setFocusPolicy(Qt.NoFocus)
        self.horizontalLayout.addWidget(self.tool_button_max)
        self.tool_button_exit = QToolButton(self.central_widget)
        self.tool_button_exit.setIcon(QIcon('.\\close.ico'))
        self.tool_button_exit.setIconSize(QSize(20, 20))
        self.tool_button_exit.setStyleSheet(
            'QToolButton { background-color: transparent;'
            'height: 20px; width: 20px; }')
        self.tool_button_exit.setFocusPolicy(Qt.NoFocus)
        self.horizontalLayout.addWidget(self.tool_button_exit)
        self.v_layout_main_window.addWidget(self.widget_title)
        self.v_layout_tree_view = QVBoxLayout()
        self.v_layout_tree_view.setContentsMargins(9, 0, 9, 9)
        self.v_layout_tree_view.setSpacing(6)
        self.h_layout_filter = QHBoxLayout()
        self.combo_box_group_name = QComboBox(self.central_widget)
        self.combo_box_group_name.setMinimumSize(QSize(120, 24))
        self.combo_box_group_name.setMaximumSize(QSize(120, 24))
        self.h_layout_filter.addWidget(self.combo_box_group_name)
        self.line_edit_key_filter = QLineEdit(self.central_widget)
        self.line_edit_key_filter.setMinimumSize(QSize(0, 24))
        self.line_edit_key_filter.setMaximumSize(QSize(16777215, 24))
        self.h_layout_filter.addWidget(self.line_edit_key_filter)
        self.combo_box_item_click_response = QComboBox(self.central_widget)
        self.combo_box_item_click_response.setMinimumSize(QSize(90, 24))
        self.combo_box_item_click_response.setMaximumSize(QSize(90, 24))
        self.combo_box_item_click_response.addItems(['复制', '复制并粘贴', '编辑'])
        self.h_layout_filter.addWidget(self.combo_box_item_click_response)
        self.v_layout_tree_view.addLayout(self.h_layout_filter)
        self.tree_widget_content_view = QTreeWidget(self.central_widget)
        self.tree_widget_content_view.header().setSectionResizeMode(
            QHeaderView.Stretch)
        self.tree_widget_content_view.setColumnCount(2)
        self.tree_widget_content_view.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.v_layout_tree_view.addWidget(self.tree_widget_content_view)
        self.v_layout_main_window.addLayout(self.v_layout_tree_view)
        self.setCentralWidget(self.central_widget)

        self.translate()

        self.tree_widget_content_view.itemClicked.connect(
            self.item_click_response)

        self.combo_box_group_name.currentIndexChanged.connect(
            self.group_filter)
        self.line_edit_key_filter.textChanged.connect(self.search_para)
        self.tool_button_top.clicked.connect(self.top_window)
        self.tool_button_max.clicked.connect(self.max_window)
        self.tool_button_min.clicked.connect(self.min_window)
        self.tool_button_exit.clicked.connect(self.close_window)

        self.display_clip_board_database()
        # self.create_clip_board_database()

    # 添加内容
    def add_clip_content(self):
        add_content = self.clip_board.text()
        if add_content:
            result = None
            try:
                result = self.db_cursor.execute(
                    '''SELECT KEY FROM CLIPBOARD WHERE CONTENT = \'%s\' ''' %
                    add_content)
            except sqlite3.OperationalError as error:
                QMessageBox.information(self, '提示', str(error))
            if result:
                # 判断结果中是否有内容
                result_info = ''
                for row in result:
                    result_info += row[0] + '\n'
                if not result_info:
                    group_list = [gp for gp in self.get_database_dict()]
                    dialog = CreateContentDialog(self, group_list, add_content)
                    return_signal = dialog.exec_()
                    if return_signal == QDialog.Accepted:
                        group, key, content = dialog.add_content
                        self.add_clip_content_to_db(group, key, content)
                        self.display_clip_board_database()
                else:
                    result_info = '内容已存在以下关键字中:\n' + result_info
                    QMessageBox.information(self, '提示', result_info)

    # 添加内容到数据库
    def add_clip_content_to_db(self, group, key, content):
        self.db_cursor.execute(
            '''INSERT INTO CLIPBOARD (CONTENT_GROUP,KEY,CONTENT)
            VALUES (\'%s\', \'%s\', \'%s\')''' % (group, key, content))
        self.db_conn.commit()

    def close_window(self):
        QMainWindow.close(self)

    # 重载窗口关闭事件
    def closeEvent(self, event: QCloseEvent):
        if self.tray_icon.isVisible():
            origin_status_top = False
            if self.is_top:
                origin_status_top = True
                self.top_window()
            dialog = ExitDialog()
            dialog.exec_()
            if dialog.status == 1:
                QApplication.quit()
            elif dialog.status == 2:
                if origin_status_top:
                    self.top_window()
                self.hide()
                event.ignore()
            else:
                if origin_status_top:
                    self.top_window()
                event.ignore()
        # message = QMessageBox.warning(self, '退出', '''<p>确定要退出吗?''',
        #                               QMessageBox.Yes | QMessageBox.No)
        # if message == QMessageBox.Yes:
        #     event.accept()
        #     self.db_conn.close()
        # else:
        #     event.ignore()

    def create_clip_board_database(self):
        self.db_cursor.execute('''CREATE TABLE CLIPBOARD(
            CONTENT_GROUP TEXT NOT NULL,
            KEY TEXT NOT NULL,
            CONTENT TEXT NOT NULL);''')
        self.db_conn.commit()
        self.db_cursor.execute(
            '''INSERT INTO CLIPBOARD (CONTENT_GROUP,KEY,CONTENT)
            VALUES (\'TEST_GROUP\', \'TEST_KEY\', \'TEST_CONTENT\')''')
        self.db_conn.commit()

    # 删除所选的内容
    def delete_contents(self):
        items = self.tree_widget_content_view.selectedItems()
        if items:
            message = QMessageBox.warning(self, '删除', '确定要删除所选组和内容吗?',
                                          QMessageBox.Yes | QMessageBox.No)
            if message == QMessageBox.Yes:
                for item in items:
                    if item.parent():
                        self.delete_content_in_database(
                            item.parent().text(0), item.text(0), item.text(1))
                    else:
                        self.delete_group_in_database(item.text(0))
                self.display_clip_board_database()

    # 删除数据库中的一条内容
    def delete_content_in_database(self, group, key, content):
        self.db_cursor.execute('''DELETE FROM CLIPBOARD WHERE
            CONTENT_GROUP = \'%s\' AND
            KEY = \'%s\' AND 
            CONTENT = \'%s\'''' % (group, key, content))
        self.db_conn.commit()

    # 删除数据库中的组
    def delete_group_in_database(self, group_name):
        self.db_cursor.execute('''DELETE FROM CLIPBOARD WHERE
            CONTENT_GROUP = \'%s\'''' % group_name)
        self.db_conn.commit()

    # 把数据库内容显示出来
    def display_clip_board_database(self):
        dict_content = self.get_database_dict()
        self.tree_widget_content_view.clear()
        self.combo_box_group_name.clear()
        if dict_content:
            grouplist = [gp for gp in dict_content]
            grouplist.insert(0, '全部组')
            self.combo_box_group_name.addItems(grouplist)
        for group_name in dict_content:
            top_item = QTreeWidgetItem(self.tree_widget_content_view)
            top_item.setText(0, group_name)
            for key_name, content in dict_content[group_name]:
                child_item = QTreeWidgetItem(top_item)
                child_item.setText(0, key_name)
                child_item.setText(1, content)
        if self.tree_widget_content_view.topLevelItemCount():
            self.tree_widget_content_view.expandAll()

    # 获得所有的数据存储在字典中
    def get_database_dict(self):
        dict_content = dict()
        data_rows = self.db_cursor.execute(
            '''SELECT CONTENT_GROUP,KEY,CONTENT FROM CLIPBOARD''')
        for row in data_rows:
            if row[0] not in dict_content:
                dict_content[row[0]] = list()
            dict_content[row[0]].append((row[1], row[2]))
        return dict_content

    # 按组过滤
    def group_filter(self, index):
        text = self.combo_box_group_name.itemText(index)
        count = self.tree_widget_content_view.topLevelItemCount()
        for i in range(count):
            item = self.tree_widget_content_view.topLevelItem(i)
            if text == '全部组':
                item.setHidden(False)
            else:
                if text != item.text(0):
                    item.setHidden(True)
                else:
                    item.setHidden(False)

    # 设置热键
    def keyPressEvent(self, event: QKeyEvent):
        if event.key() == Qt.Key_V:
            if event.modifiers() == Qt.ControlModifier:
                self.add_clip_content()
                event.accept()
        if event.key() == Qt.Key_R:
            if event.modifiers() == Qt.ControlModifier:
                if self.tree_widget_content_view.topLevelItemCount():
                    self.tree_widget_content_view.collapseAll()
                event.accept()
        if event.key() == Qt.Key_E:
            if event.modifiers() == Qt.ControlModifier:
                if self.tree_widget_content_view.topLevelItemCount():
                    self.tree_widget_content_view.expandAll()
                event.accept()
        if event.key() == Qt.Key_Delete:
            self.delete_contents()
        else:
            event.ignore()

    # 最大化窗口
    def max_window(self):
        if self.isMaximized():
            self.showNormal()
            self.tool_button_max.setIcon(QIcon('.\\max.ico'))
        else:
            self.showMaximized()
            self.tool_button_max.setIcon(QIcon('.\\normal.ico'))

    # 最小化窗口
    def min_window(self):
        if not self.isMinimized():
            self.showMinimized()

    # 实现窗口拖动
    def mousePressEvent(self, event: QMouseEvent):
        if event.button() == Qt.LeftButton:
            self.on_move = True
            self.mouse_start_point = event.globalPos()
            self.window_geo = self.frameGeometry()
            if self.mouse_start_point.x() <= self.window_geo.left() + 9:
                if self.mouse_start_point.y() <= self.window_geo.top() + 9:
                    self.window_status = 'top_left'
                    self.setCursor(Qt.SizeFDiagCursor)
                elif self.mouse_start_point.y(
                ) >= self.window_geo.bottom() - 9:
                    self.window_status = 'bottom_left'
                    self.setCursor(Qt.SizeBDiagCursor)
                else:
                    self.window_status = 'left'
                    self.setCursor(Qt.SizeHorCursor)
            elif self.mouse_start_point.x() >= self.window_geo.right() - 9:
                if self.mouse_start_point.y() <= self.window_geo.top() + 9:
                    self.window_status = 'top_right'
                    self.setCursor(Qt.SizeBDiagCursor)
                elif self.mouse_start_point.y(
                ) >= self.window_geo.bottom() - 9:
                    self.window_status = 'bottom_right'
                    self.setCursor(Qt.SizeFDiagCursor)
                else:
                    self.window_status = 'right'
                    self.setCursor(Qt.SizeHorCursor)
            elif self.mouse_start_point.y() <= self.window_geo.top() + 9:
                self.window_status = 'top'
                self.setCursor(Qt.SizeVerCursor)
            elif self.mouse_start_point.y() >= self.window_geo.bottom() - 9:
                self.window_status = 'bottom'
                self.setCursor(Qt.SizeVerCursor)
            else:
                self.window_status = 'move'
        QMainWindow.mousePressEvent(self, event)

    def mouseMoveEvent(self, event: QMouseEvent):
        if event.buttons() and Qt.LeftButton and self.on_move:
            relative_pos = event.globalPos() - self.mouse_start_point
            if self.window_status == 'left':
                width = self.window_geo.right() - self.window_geo.left(
                ) - relative_pos.x()
                if width > self.window_width:
                    self.setGeometry(self.window_geo.left() + relative_pos.x(),
                                     self.window_geo.top(), width,
                                     self.window_geo.height())
            if self.window_status == 'right':
                width = self.window_geo.width() + relative_pos.x()
                if width > self.window_width:
                    self.setGeometry(self.window_geo.left(),
                                     self.window_geo.top(), width,
                                     self.window_geo.height())
            if self.window_status == 'top':
                height = self.window_geo.bottom() - self.window_geo.top(
                ) - relative_pos.y()
                if height > self.window_height:
                    self.setGeometry(self.window_geo.left(),
                                     self.window_geo.top() + relative_pos.y(),
                                     self.window_geo.width(), height)
            if self.window_status == 'bottom':
                height = self.window_geo.height() + relative_pos.y()
                if height > self.window_height:
                    self.setGeometry(self.window_geo.left(),
                                     self.window_geo.top(),
                                     self.window_geo.width(), height)
            if self.window_status == 'top_left':
                width = self.window_geo.right() - self.window_geo.left(
                ) - relative_pos.x()
                height = self.window_geo.bottom() - self.window_geo.top(
                ) - relative_pos.y()
                if width > self.window_width and height > self.window_height:
                    self.setGeometry(self.window_geo.left() + relative_pos.x(),
                                     self.window_geo.top() + relative_pos.y(),
                                     width, height)
            if self.window_status == 'top_right':
                width = self.window_geo.width() + relative_pos.x()
                height = self.window_geo.bottom() - self.window_geo.top(
                ) - relative_pos.y()
                if width > self.window_width and height > self.window_height:
                    self.setGeometry(self.window_geo.left(),
                                     self.window_geo.top() + relative_pos.y(),
                                     width, height)
            if self.window_status == 'bottom_right':
                width = self.window_geo.width() + relative_pos.x()
                height = self.window_geo.height() + relative_pos.y()
                if width > self.window_width and height > self.window_height:
                    self.setGeometry(self.window_geo.left(),
                                     self.window_geo.top(), width, height)
            if self.window_status == 'bottom_left':
                width = self.window_geo.right() - self.window_geo.left(
                ) - relative_pos.x()
                height = self.window_geo.height() + relative_pos.y()
                if width > self.window_width and height > self.window_height:
                    self.setGeometry(self.window_geo.left() + relative_pos.x(),
                                     self.window_geo.top(), width, height)
            if self.window_status == 'move':
                self.move(self.window_geo.topLeft() + relative_pos)
        QMainWindow.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event: QMouseEvent):
        if event.button() == Qt.LeftButton:
            # 改变移动状态
            self.window_status = ''
            self.on_move = False
            self.mouse_start_point = None
            self.window_geo = None
            self.setCursor(Qt.ArrowCursor)
        QMainWindow.mouseReleaseEvent(self, event)

    # 单击托盘时的响应
    def restore_win(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            if self.isHidden():
                self.show()
            self.activateWindow()

    # 搜索参数并显示在参数窗口里
    def search_para(self, key_name):
        text = self.combo_box_group_name.currentText()
        index = self.combo_box_group_name.currentIndex() - 1
        pattern = re.compile('.*' + key_name + '.*', re.I)
        if text == '全部组':
            count = self.tree_widget_content_view.topLevelItemCount()
            for i in range(count):
                num_key_in_show = 0
                item = self.tree_widget_content_view.topLevelItem(i)
                child_count = item.childCount()
                for child_index in range(child_count):
                    kn = item.child(child_index).text(0)
                    if re.match(pattern, kn):
                        item.child(child_index).setHidden(False)
                        num_key_in_show += 1
                    else:
                        item.child(child_index).setHidden(True)
                if num_key_in_show == 0:
                    item.setHidden(True)
                else:
                    item.setHidden(False)
        else:
            num_key_in_show = 0
            item = self.tree_widget_content_view.topLevelItem(index)
            child_count = item.childCount()
            for child_index in range(child_count):
                kn = item.child(child_index).text(0)
                if re.match(pattern, kn):
                    item.child(child_index).setHidden(False)
                    num_key_in_show += 1
                else:
                    item.child(child_index).setHidden(True)
            if num_key_in_show == 0:
                item.setHidden(True)
            else:
                item.setHidden(False)
        self.tree_widget_content_view.expandAll()

    # 将选中的内容添加到剪贴板中
    def item_click_response(self, item):
        if self.combo_box_item_click_response.currentText() == '编辑':
            if item.parent():
                group_list = [gp for gp in self.get_database_dict()]
                old_content = (item.parent().text(0), item.text(0),
                               item.text(1))
                dialog = EditContentDialog(self, group_list, old_content)
                return_signal = dialog.exec_()
                if return_signal == QDialog.Accepted:
                    if old_content != dialog.add_content:
                        old_group, old_key, old_content = old_content
                        group, key, content = dialog.add_content
                        self.db_cursor.execute(
                            '''UPDATE CLIPBOARD SET CONTENT_GROUP = \'%s\', 
                            KEY = \'%s\', CONTENT = \'%s\' 
                            WHERE CONTENT_GROUP = \'%s\' AND 
                            KEY = \'%s\' AND 
                            CONTENT = \'%s\'''' %
                            (group, key, content, old_group, old_key,
                             old_content))
                        self.db_conn.commit()
                        self.display_clip_board_database()
        elif self.combo_box_item_click_response.currentText() == '复制':
            if item.parent():
                self.clip_board.setText(item.text(1))
        elif self.combo_box_item_click_response.currentText() == '复制并粘贴':
            if item.parent():
                self.clip_board.setText(item.text(1))
                focus_win_hwnd = xx = win32gui.GetFocus()
                hwnd_title = dict()

                def get_all_window(hwnd, mouse):

                    if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and\
                            win32gui.IsWindowVisible(hwnd):
                        hwnd_title.update({hwnd: win32gui.GetWindowText(hwnd)})

                win32gui.EnumWindows(get_all_window, 1)
                if hwnd_title:
                    hwnd_list = [h for h, t in hwnd_title.items()]
                    index = hwnd_list.index(focus_win_hwnd)
                    if self.is_top:
                        if index < len(hwnd_list) - 2:
                            focus_win_hwnd = hwnd_list[index + 2]
                            win32gui.SetForegroundWindow(focus_win_hwnd)
                            win32api.keybd_event(17, 0, 0, 0)
                            win32api.keybd_event(86, 0, 0, 0)
                            win32api.keybd_event(86, 0,
                                                 win32con.KEYEVENTF_KEYUP, 0)
                            win32api.keybd_event(17, 0,
                                                 win32con.KEYEVENTF_KEYUP, 0)
                            win32api.keybd_event(13, 0, 0, 0)
                            win32api.keybd_event(13, 0,
                                                 win32con.KEYEVENTF_KEYUP, 0)
                    else:
                        if index < len(hwnd_list) - 1:
                            focus_win_hwnd = hwnd_list[index + 1]
                            win32gui.SetForegroundWindow(focus_win_hwnd)
                            win32api.keybd_event(17, 0, 0, 0)
                            win32api.keybd_event(86, 0, 0, 0)
                            win32api.keybd_event(86, 0,
                                                 win32con.KEYEVENTF_KEYUP, 0)
                            win32api.keybd_event(17, 0,
                                                 win32con.KEYEVENTF_KEYUP, 0)
                            win32api.keybd_event(13, 0, 0, 0)
                            win32api.keybd_event(13, 0,
                                                 win32con.KEYEVENTF_KEYUP, 0)
        else:
            pass

    def top_window(self):
        if self.is_top:
            self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint
                                | Qt.MSWindowsOwnDC)
            self.show()
            self.is_top = False
            self.tool_button_top.setIcon(QIcon('.\\top.ico'))
        else:
            self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint
                                | Qt.WindowStaysOnTopHint)
            self.show()
            self.is_top = True
            self.tool_button_top.setIcon(QIcon('.\\un_top.ico'))

    # 汉化
    def translate(self):
        self.setWindowTitle("MainWindow")
        self.tool_button_top.setToolTip('置顶')
        # self.tool_button_back.setToolTip('后台运行')
        self.tool_button_min.setToolTip('最小化')
        self.tool_button_max.setToolTip('最大化')
        self.tool_button_exit.setToolTip('关闭')
        self.line_edit_key_filter.setPlaceholderText("筛选器")
        self.tree_widget_content_view.headerItem().setText(0, '关键字')
        self.tree_widget_content_view.headerItem().setText(1, '内容')
Beispiel #9
0
class WithTrayIcon(QDialog):

    user_closed = False

    def setupSysTray(self):
        self._createIcons()
        self._createActions()
        self._createTrayIcon()
        self.trayIcon.activated.connect(self.iconActivated)
        self.setVPNStatus('off')
        self.setUpEventListener()
        self.trayIcon.show()

    def setVPNStatus(self, status):
        seticon = self.trayIcon.setIcon
        settip = self.trayIcon.setToolTip
        # XXX this is an oversimplification, see #9131
        # the simple state for failure is off too, for now.
        if status == 'off':
            seticon(self.ICON_OFF)
            settip('VPN: Off')
        elif status == 'on':
            seticon(self.ICON_ON)
            settip('VPN: On')
        elif status == 'starting':
            seticon(self.ICON_WAIT)
            settip('VPN: Starting')
        elif status == 'stopping':
            seticon(self.ICON_WAIT)
            settip('VPN: Stopping')

    def setUpEventListener(self):
        leap_events.register(catalog.VPN_STATUS_CHANGED,
                             self._handle_vpn_event)

    def _handle_vpn_event(self, *args):
        status = None
        if len(args) > 1:
            status = args[1]
            self.setVPNStatus(status.lower())

    def _createIcons(self):
        self.ICON_WAIT = QIcon(QPixmap(TRAY_ICONS[0]))
        self.ICON_ON = QIcon(QPixmap(TRAY_ICONS[1]))
        self.ICON_OFF = QIcon(QPixmap(TRAY_ICONS[2]))

    def _createActions(self):
        self.quitAction = QAction("&Quit",
                                  self,
                                  triggered=self.closeFromSystray)

    def iconActivated(self, reason):
        # can use .Trigger also for single click
        if reason in (QSystemTrayIcon.DoubleClick, ):
            self.showNormal()

    def closeFromSystray(self):
        self.user_closed = True
        self.close()

    def _createTrayIcon(self):
        self.trayIconMenu = QMenu(self)
        self.trayIconMenu.addAction(self.quitAction)
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setContextMenu(self.trayIconMenu)

    def closeEvent(self, event):
        if self.trayIcon.isVisible() and not self.user_closed:
            QMessageBox.information(
                self, "Bitmask", "Bitmask will minimize to the system tray. "
                "You can choose 'Quit' from the menu with a "
                "right click on the icon, and restore the window "
                "with a double click.")
        self.hide()
        if not self.user_closed:
            event.ignore()
Beispiel #10
0
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(QMainWindow, self).__init__()
        # Set up the user interface from Designer.
        self.setupUi(self)

        self.setAccessibleName("Hive Desktop")
        self.redrawLock = Lock()
        self.updateLock = Lock()

        self.optionsDialog = dialogs.Options(self)
        self.aboutDialog = dialogs.About(
            self,
            copyright='holger80',
            programName='Hive Desktop',
            version=VERSION,
            website='https://github.com/holgern/hivedesktop',
            websiteLabel='Github',
            comments=
            '"Welcome to Hive desktop!\n This is the first release for testing qt5.\n Please vote for holger80 as witness, if you like this :).',
            licenseName='GPL-3.0',
            # licenseUrl=helpers.joinpath_to_cwd('LICENSE').as_uri(),
            authors=('holger80', ),
            # dependencies=[l.strip() for l in requirements.readlines()],
        )
        self.mdrenderer = MDRenderer(str(helpers.joinpath_to_cwd('themes')))

        # tmpfile = helpers.mktemp(prefix='hivedesktop', suffix='.html')

        self.post = {"body": "##test", "authorperm": "@test/test"}
        self.thread = threads.MDThread(self)

        # self.webview.url = tmpfile.as_uri()

        self.feedListWidget.currentRowChanged.connect(
            self.change_displayed_post, Qt.QueuedConnection)

        self.timer = QTimer()
        self.timer.timeout.connect(self.refresh_account_thread)

        self.timer2 = QTimer()
        self.timer2.timeout.connect(self.update_account_hist_thread)

        self.timer3 = QTimer()
        self.timer3.timeout.connect(self.update_account_feed_thread)

        self.cache_path = QStandardPaths.writableLocation(
            QStandardPaths.CacheLocation)
        self.db_type = "shelve"
        self.feed = []
        self.post = None
        # Get settings
        settings = QSettings()
        # Get checkbox state with speciying type of checkbox:
        # type=bool is a replacement of toBool() in PyQt5
        check_state = settings.value(SETTINGS_TRAY, True, type=bool)
        hist_info_check_state = settings.value(SETTINGS_HIST_INFO,
                                               True,
                                               type=bool)
        account_state = settings.value(SETTINGS_ACCOUNT, "", type=str)
        # Set state
        self.accountHistNotificationCheckBox.setChecked(hist_info_check_state)
        self.autoRefreshCheckBox.setChecked(check_state)
        if check_state:
            self.timer.start(5000)
            self.timer2.start(15000)
            self.timer3.start(60000)
        self.accountLineEdit.setText(account_state)
        # connect the slot to the signal by clicking the checkbox to save the state settings
        self.autoRefreshCheckBox.clicked.connect(self.save_check_box_settings)
        self.accountHistNotificationCheckBox.clicked.connect(
            self.save_check_box_settings)
        self.accountLineEdit.editingFinished.connect(
            self.save_account_settings)
        self.actionAbout.triggered.connect(self.about)
        self.actionOptions.triggered.connect(self.options)
        self.threadpool = QThreadPool()

        self.minimizeAction = QAction("Mi&nimize", self, triggered=self.hide)
        self.maximizeAction = QAction("Ma&ximize",
                                      self,
                                      triggered=self.showMaximized)
        self.restoreAction = QAction("&Restore",
                                     self,
                                     triggered=self.showNormal)

        menu = QMenu()
        menu.addAction(self.minimizeAction)
        menu.addAction(self.maximizeAction)
        menu.addAction(self.restoreAction)
        menu.addSeparator()
        # aboutAction = menu.addAction("about")
        # aboutAction.triggered.connect(self.about)
        exitAction = menu.addAction("Exit")
        exitAction.triggered.connect(self.closeApp)

        self.tray = QSystemTrayIcon(QIcon(':/icons/icon.ico'))

        self.tray.setContextMenu(menu)

        self.tray.setToolTip("Hive Desktop!")
        self.tray.setObjectName("Hive Desktop")
        self.setWindowTitle("Hive Desktop")
        self.tray.show()

        splash_pix = QPixmap(':/icons/splash.png')
        splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
        splash.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
        splash.setEnabled(False)

        splash.show()
        splash.showMessage("<h1><font color='green'>starting...</font></h1>",
                           Qt.AlignTop | Qt.AlignCenter, Qt.black)

        account = account_state
        nodelist = NodeList()
        nodelist.update_nodes()
        self.stm = Steem(node=nodelist.get_nodes(hive=True))
        if account != "":
            try:
                self.hist_account = Account(account, steem_instance=self.stm)
            except:
                self.hist_account = None
        else:
            self.hist_account = None
        if self.hasFocus is not None:
            self.init_new_account()
        # self.button.clicked.connect(lambda: self.text.setText(_get_quote(self.hist_account, self.stm)))
        self.refreshPushButton.clicked.connect(self.refresh_account_thread)
        self.refreshPushButton.clicked.connect(self.update_account_hist_thread)
        self.accountLineEdit.editingFinished.connect(self.update_account_info)
        splash.deleteLater()
        self.tray.showMessage("Ready", "Account history loaded!")

    def triggeredPreview(self):
        self.authorLabel.setText(self.post["author"])
        self.titleLabel.setText(self.post["title"])
        self.thread.start()

    @pyqtSlot(str)
    def cbMDThread(self, html):
        self.webview.setHtml(html)

    def closeEvent(self, event):
        if self.tray.isVisible():
            QMessageBox.information(
                self, "Hive Desktop",
                "The program will keep running in the system tray. To "
                "terminate the program, choose <b>Quit</b> in the "
                "context menu of the system tray entry.")
            self.hide()
            event.ignore()

    def closeApp(self):
        self.store_account_hist()
        sys.exit()

    def about(self):
        self.aboutDialog.exec_()

    def options(self):
        self.optionsDialog.exec_()

    # Slot checkbox to save the settings
    def save_check_box_settings(self):
        settings = QSettings()
        settings.setValue(SETTINGS_HIST_INFO,
                          self.accountHistNotificationCheckBox.isChecked())
        settings.setValue(SETTINGS_TRAY, self.autoRefreshCheckBox.isChecked())
        if self.autoRefreshCheckBox.isChecked():
            self.timer.start(5000)
            self.timer2.start(15000)
            self.timer3.start(60000)
        else:
            self.timer.stop()
            self.timer2.stop()
            self.timer3.stop()
        settings.sync()

    # Slot checkbox to save the settings
    def save_account_settings(self):
        settings = QSettings()
        settings.setValue(SETTINGS_ACCOUNT, self.accountLineEdit.text())
        settings.sync()

    def update_account_info(self):
        if self.hist_account is None or self.hist_account[
                "name"] != self.accountLineEdit.text():
            self.store_account_hist()
            try:
                self.hist_account = Account(self.accountLineEdit.text(),
                                            steem_instance=self.stm)
            except:
                self.hist_account = None
            self.init_new_account()

    def init_new_account(self):
        if self.hist_account is not None:
            self.db = database.Database(self.db_type, self.cache_path,
                                        self.hist_account["name"])
        self.refresh_account()
        self.init_account_hist()
        self.update_account_hist()
        self.update_account_feed()
        self.store_account_hist()

    def refresh_account_thread(self):
        worker = Worker(self.refresh_account)
        self.threadpool.start(worker)

    def refresh_account(self):
        if self.hist_account is None:
            return
        self.hist_account.refresh()
        self.accountInfoGroupBox.setTitle(
            "%s (%.3f)" % (self.hist_account["name"], self.hist_account.rep))
        with self.redrawLock:
            self.votePowerProgressBar.setValue(int(self.hist_account.vp))
            if self.hist_account.vp == 100:
                self.votePowerProgressBar.setFormat("%.2f %%" %
                                                    (self.hist_account.vp))
            else:
                self.votePowerProgressBar.setFormat(
                    "%.2f %%, full in %s" %
                    (self.hist_account.vp,
                     self.hist_account.get_recharge_time_str()))
        down_vp = self.hist_account.get_downvoting_power()
        with self.redrawLock:
            self.downvotePowerProgressBar.setValue(int(down_vp))
            if down_vp == 100:
                self.downvotePowerProgressBar.setFormat("%.2f %%" % (down_vp))
            else:
                self.downvotePowerProgressBar.setFormat(
                    "%.2f %%, full in %s" %
                    (down_vp,
                     self.hist_account.get_recharge_time(
                         starting_voting_power=down_vp)))

        self.votePowerLabel.setText("Vote Power, a 100%% vote is %.3f $" %
                                    (self.hist_account.get_voting_value_SBD()))
        self.downvotePowerLabel.setText("DownVote Power")
        self.STEEMLabel.setText(str(self.hist_account["balance"]))
        self.SBDLabel.setText(str(self.hist_account["sbd_balance"]))
        self.SPLabel.setText(
            "%.3f HP" %
            self.stm.vests_to_sp(self.hist_account["vesting_shares"]))
        try:
            rc_manabar = self.hist_account.get_rc_manabar()
            with self.redrawLock:
                self.RCProgressBar.setValue(int(rc_manabar["current_pct"]))
                self.RCProgressBar.setFormat(
                    "%.2f %%, full in %s" %
                    (rc_manabar["current_pct"],
                     self.hist_account.get_manabar_recharge_time_str(
                         rc_manabar)))

            rc = self.hist_account.get_rc()
            estimated_rc = int(rc["max_rc"]) * rc_manabar["current_pct"] / 100
            rc_calc = RC(steem_instance=self.stm)
            self.RCLabel.setText(
                "RC (%.0f G RC of %.0f G RC)" %
                (estimated_rc / 10**9, int(rc["max_rc"]) / 10**9))
            ret = "--- Approx Costs ---\n"
            ret += "comment - %.2f G RC - enough RC for %d comments\n" % (
                rc_calc.comment() / 10**9, int(
                    estimated_rc / rc_calc.comment()))
            ret += "vote - %.2f G RC - enough RC for %d votes\n" % (
                rc_calc.vote() / 10**9, int(estimated_rc / rc_calc.vote()))
            ret += "transfer - %.2f G RC - enough RC for %d transfers\n" % (
                rc_calc.transfer() / 10**9,
                int(estimated_rc / rc_calc.transfer()))
            ret += "custom_json - %.2f G RC - enough RC for %d custom_json\n" % (
                rc_calc.custom_json() / 10**9,
                int(estimated_rc / rc_calc.custom_json()))
            self.text.setText(ret)
        except:
            rc_manabar = None

    def store_account_hist(self):
        if self.hist_account is None:
            return
        self.db.store_account_hist(self.account_history,
                                   self.append_hist_info["trx_ids"])

    def init_account_hist(self):
        if self.hist_account is None:
            return
        b = Blockchain(steem_instance=self.stm)
        latest_block_num = b.get_current_block_num()
        start_block_num = latest_block_num - (20 * 60 * 24)
        self.account_history = []
        self.account_hist_info = {"start_block": 0, "trx_ids": []}
        self.append_hist_info = {"start_block": 0, "trx_ids": []}

        if self.db.has_account_hist():
            self.account_history, trx_ids = self.db.load_account_hist()
            if self.account_history[0]["block"] <= start_block_num:
                self.append_hist_info["start_block"] = self.account_history[
                    -1]["block"]
                self.append_hist_info["trx_ids"] = trx_ids
                return

        self.lastUpvotesListWidget.clear()
        self.lastCurationListWidget.clear()
        self.lastAuthorListWidget.clear()
        self.accountHistListWidget.clear()
        start_block = 0
        trx_ids = []
        for op in self.hist_account.history(start=start_block_num):
            if op["block"] < start_block:
                continue
            elif op["block"] == start_block:
                if op["trx_id"] in trx_ids:
                    continue
                else:
                    trx_ids.append(op["trx_id"])
            else:
                trx_ids = [op["trx_id"]]
            start_block = op["block"]
            self.account_history.append(op)
        self.append_hist_info["start_block"] = start_block
        self.append_hist_info["trx_ids"] = trx_ids

    def append_account_hist(self):
        if self.hist_account is None:
            return
        start_block = self.append_hist_info["start_block"]
        trx_ids = self.append_hist_info["trx_ids"]
        for op in self.hist_account.history(start=start_block - 20,
                                            use_block_num=True):
            if op["block"] < start_block:
                continue
            elif op["block"] == start_block:
                if op["trx_id"] in trx_ids:
                    continue
                else:
                    trx_ids.append(op["trx_id"])
            else:
                trx_ids = [op["trx_id"]]

            start_block = op["block"]
            # print("Write %d" % op["index"])
            self.account_history.append(op)
        self.append_hist_info["start_block"] = start_block
        self.append_hist_info["trx_ids"] = trx_ids

    def update_account_hist_thread(self):
        worker = Worker(self.update_account_hist)
        self.threadpool.start(worker)

    def update_account_feed_thread(self):
        worker = Worker(self.update_account_feed)
        self.threadpool.start(worker)

    @pyqtSlot(int)
    def change_displayed_post(self, row):
        if row < 0:
            return
        if len(self.feed) == 0:
            return
        if len(self.feed) <= row:
            return
        #index = self.feedListWidget.currentIndex()
        #row = index.row()
        self.post = self.feed[row]
        with self.updateLock:
            self.triggeredPreview()

    def update_account_feed(self):
        if self.hist_account is None:
            return
        updated_feed = self.hist_account.get_account_posts()
        if len(self.feed) == 0:
            self.feed = updated_feed
        else:
            for post in updated_feed[::-1]:
                found = False
                for p in self.feed:
                    if post["authorperm"] == p["authorperm"]:
                        found = True
                if not found:
                    self.feed.insert(0, post)
                    self.tray.showMessage(post["author"], post["title"])
        with self.updateLock:
            if self.post is None:
                self.post = self.feed[0]
                self.triggeredPreview()

            self.feedListWidget.currentRowChanged.disconnect(
                self.change_displayed_post)
            self.feedListWidget.clear()
            for post in self.feed[::-1]:
                post_text = "%s - %s" % (post["author"], post["title"])
                post_item = QListWidgetItem()
                post_item.setText(post_text)
                post_item.setToolTip(post["author"])
                self.feedListWidget.insertItem(0, post_item)
            self.feedListWidget.currentRowChanged.connect(
                self.change_displayed_post, Qt.QueuedConnection)

    def update_account_hist(self):
        if self.hist_account is None:
            return
        votes = []
        daily_curation = 0
        daily_author_SP = 0
        daily_author_SBD = 0
        daily_author_STEEM = 0
        self.append_account_hist()

        new_op_found = False

        start_block = self.account_hist_info["start_block"]
        if start_block == 0:
            first_call = True
        else:
            first_call = False
        trx_ids = self.account_hist_info["trx_ids"]

        for op in self.account_history:
            if op["block"] < start_block:
                # last_block = op["block"]
                continue
            elif op["block"] == start_block:
                if op["trx_id"] in trx_ids:
                    continue
                else:
                    trx_ids.append(op["trx_id"])
            else:
                trx_ids = [op["trx_id"]]
            start_block = op["block"]
            new_op_found = True
            op_timedelta = formatTimedelta(
                addTzInfo(datetime.utcnow()) -
                formatTimeString(op["timestamp"]))
            op_local_time = formatTimeString(op["timestamp"]).astimezone(
                tz.tzlocal())
            # print("Read %d" % op["index"])
            if op["type"] == "vote":
                if op["voter"] == self.hist_account["name"]:
                    continue
                if op["weight"] >= 0:

                    self.lastUpvotesListWidget.insertItem(
                        0, "%s - %s (%.2f %%) upvote %s" %
                        (op_timedelta, op["voter"], op["weight"] / 100,
                         op["permlink"]))
                    hist_item = "%s - %s - %s (%.2f %%) upvote %s" % (
                        op_local_time, op["type"], op["voter"],
                        op["weight"] / 100, op["permlink"])
                    tray_item = "%s - %s (%.2f %%) upvote %s" % (
                        op["type"], op["voter"], op["weight"] / 100,
                        op["permlink"])
                else:
                    hist_item = "%s - %s - %s (%.2f %%) downvote %s" % (
                        op_local_time, op["type"], op["voter"],
                        op["weight"] / 100, op["permlink"])
                    tray_item = "%s - %s (%.2f %%) downvote %s" % (
                        op["type"], op["voter"], op["weight"] / 100,
                        op["permlink"])

                self.accountHistListWidget.insertItem(0, hist_item)
            elif op["type"] == "curation_reward":
                curation_reward = self.stm.vests_to_sp(
                    Amount(op["reward"], steem_instance=self.stm))
                self.lastCurationListWidget.insertItem(
                    0, "%s - %.3f HP for %s" %
                    (op_timedelta, curation_reward,
                     construct_authorperm(op["comment_author"],
                                          op["comment_permlink"])))
                hist_item = "%s - %s - %.3f HP for %s" % (
                    op_local_time, op["type"], curation_reward,
                    construct_authorperm(op["comment_author"],
                                         op["comment_permlink"]))
                tray_item = "%s - %.3f HP for %s" % (
                    op["type"], curation_reward,
                    construct_authorperm(op["comment_author"],
                                         op["comment_permlink"]))
                self.accountHistListWidget.insertItem(0, hist_item)
            elif op["type"] == "author_reward":
                sbd_payout = (Amount(op["sbd_payout"],
                                     steem_instance=self.stm))
                steem_payout = (Amount(op["steem_payout"],
                                       steem_instance=self.stm))
                sp_payout = self.stm.vests_to_sp(
                    Amount(op["vesting_payout"], steem_instance=self.stm))
                self.lastAuthorListWidget.insertItem(
                    0, "%s - %s %s %.3f HP for %s" %
                    (op_timedelta, str(sbd_payout), str(steem_payout),
                     sp_payout, op["permlink"]))
                hist_item = "%s - %s - %s %s %.3f SP for %s" % (
                    op_local_time, op["type"], str(sbd_payout),
                    str(steem_payout), sp_payout, op["permlink"])
                tray_item = "%s - %s %s %.3f SP for %s" % (
                    op["type"], str(sbd_payout), str(steem_payout), sp_payout,
                    op["permlink"])
                self.accountHistListWidget.insertItem(0, hist_item)
            elif op["type"] == "custom_json":
                hist_item = "%s - %s - %s" % (op_local_time, op["type"],
                                              op["id"])
                tray_item = "%s - %s" % (op["type"], op["id"])
                self.accountHistListWidget.insertItem(0, hist_item)
            elif op["type"] == "transfer":
                hist_item = "%s - %s - %s from %s" % (
                    op_local_time, op["type"],
                    str(Amount(op["amount"],
                               steem_instance=self.stm)), op["from"])
                tray_item = "%s - %s from %s" % (
                    op["type"],
                    str(Amount(op["amount"],
                               steem_instance=self.stm)), op["from"])
                self.accountHistListWidget.insertItem(0, hist_item)
            elif op["type"] == "comment":
                comment_type = "post"
                if op["parent_author"] != "":
                    hist_item = "%s - comment on %s - %s from %s" % (
                        op_local_time,
                        construct_authorperm(
                            op["parent_author"],
                            op["parent_permlink"]), op["title"], op["author"])
                    tray_item = "comment from %s: %s on %s" % (
                        op["author"], op["body"][:100], op["title"])
                else:
                    hist_item = "%s - post - %s from %s" % (
                        op_local_time, op["title"], op["author"])
                    tray_item = "post from %s: %s" % (op["author"],
                                                      op["title"])
                self.accountHistListWidget.insertItem(0, hist_item)
            else:
                hist_item = "%s - %s" % (op_local_time, op["type"])
                tray_item = "%s" % (op["type"])
                self.accountHistListWidget.insertItem(0, hist_item)

            if self.accountHistNotificationCheckBox.isChecked(
            ) and not first_call:
                self.tray.showMessage(self.hist_account["name"], tray_item)

        if new_op_found:
            self.account_hist_info["start_block"] = start_block
            self.account_hist_info["trx_ids"] = trx_ids

            for op in self.account_history:
                if op["type"] == "vote":
                    if op["voter"] == self.hist_account["name"]:
                        continue
                    votes.append(op)
                elif op["type"] == "curation_reward":
                    curation_reward = self.stm.vests_to_sp(
                        Amount(op["reward"], steem_instance=self.stm))
                    daily_curation += curation_reward
                elif op["type"] == "author_reward":
                    sbd_payout = (Amount(op["sbd_payout"],
                                         steem_instance=self.stm))
                    steem_payout = (Amount(op["steem_payout"],
                                           steem_instance=self.stm))
                    sp_payout = self.stm.vests_to_sp(
                        Amount(op["vesting_payout"], steem_instance=self.stm))
                    daily_author_SP += sp_payout
                    daily_author_STEEM += float(steem_payout)
                    daily_author_SBD += float(sbd_payout)

            reward_text = "Curation reward (last 24 h): %.3f HP\n" % daily_curation
            reward_text += "Author reward (last 24 h):\n"
            reward_text += "%.3f HP - %.3f HIVE - %.3f HBD" % (
                daily_author_SP, (daily_author_STEEM), (daily_author_SBD))
            self.text2.setText(reward_text)
Beispiel #11
0
class MainWindow(QMainWindow):
    EXIT_CODE_REBOOT = 520

    def __init__(self):
        super().__init__()
        Config.initialize()
        self.initUI()

    def initUI(self):
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.spliter = QSplitter(Qt.Vertical)
        self.spliter.addWidget(TestUnitArea())
        self.spliter.addWidget(TestResultArea())
        self.spliter.setHandleWidth(1)
        self.setCentralWidget(self.spliter)

        tool_menu = QMenu('工具', self.menuBar())
        tool_menu.addAction('数据监听', self.onDebugWindow)
        tool_menu.addAction('单步测试', self.onSingleStep)
        tool_menu.addAction('记录查询', self.onViewData)
        tool_menu.addAction('条码打印', self.onPrintBarCode)
        tool_menu.addAction('异常信息', self.onExceptionWindow)

        setting_menu = QMenu('选项', self.menuBar())
        setting_menu.addAction('参数设置', self.onSetting)
        # setting_menu.addAction('软件重启', self.onRestart)

        help_menu = QMenu('帮助', self.menuBar())
        help_menu.addAction('关于', self.onAbout)

        self.menuBar().addMenu(setting_menu)
        self.menuBar().addMenu(tool_menu)
        self.menuBar().addMenu(help_menu)

        QApplication.setWindowIcon(QIcon(Config.LOGO_IMG))
        QApplication.instance().aboutToQuit.connect(self.onApplicationQuit)
        QApplication.setOrganizationName(Config.ORGANIZATION)
        QApplication.setApplicationName(Config.APP_NAME)
        QApplication.setApplicationVersion(Config.APP_VERSION)
        self.restoreQSettings()
        self.createSystemTray()

    def onDebugWindow(self):
        if not ui.DebugDialog.prev_actived:
            self.debugWin = ui.DebugDialog()
            self.debugWin.show()
        else:
            QApplication.setActiveWindow(ui.DebugDialog.prev_window)
            ui.DebugDialog.prev_window.showNormal()

    def onSingleStep(self):
        if not ui.SingleStepFrame.prev_actived:
            self.singleWin = ui.SingleStepFrame()
            self.singleWin.show()
        else:
            QApplication.setActiveWindow(ui.SingleStepFrame.prev_window)
            ui.SingleStepFrame.prev_window.showNormal()

    def onViewData(self):
        if not ui.SearchWindow.prev_actived:
            self.searchWin = ui.SearchWindow()
            self.searchWin.show()
        else:
            QApplication.setActiveWindow(ui.SearchWindow.prev_window)
            ui.SearchWindow.prev_window.showNormal()

    def onPrintBarCode(self):
        if not CodeDialog.prev_actived:
            self.codeWin = CodeDialog()
            self.codeWin.show()
        else:
            QApplication.setActiveWindow(CodeDialog.prev_window)
            CodeDialog.prev_window.showNormal()

    def onExceptionWindow(self):
        if not ui.ExceptionWindow.prev_actived:
            self.excptionWin = ui.ExceptionWindow()
            self.excptionWin.show()
        else:
            QApplication.setActiveWindow(ui.ExceptionWindow.prev_window)
            ui.ExceptionWindow.prev_window.showNormal()

    def restoreQSettings(self):
        main_win_geo = Config.QSETTING.value('MainWindow/geometry')
        main_win_centerwgt_state = Config.QSETTING.value(
            'MainWindow/CenterWidget/state')

        if main_win_geo: self.restoreGeometry(main_win_geo)
        if main_win_centerwgt_state:
            self.spliter.restoreState(main_win_centerwgt_state)

    def onSetting(self):
        dlg = ui.SettingDialog(self)
        dlg.move(self.x() + 50, self.y() + 50)
        dlg.exec()

    def onRestart(self):
        QApplication.exit(self.EXIT_CODE_REBOOT)

    def onAbout(self):
        dlg = ui.AboutDialog(Config.ABOUT_HTML)
        dlg.resize(400, 300)
        dlg.exec()

    def createSystemTray(self):
        self.systray = QSystemTrayIcon(self)
        self.systray.setIcon(QIcon(Config.LOGO_IMG))
        self.systray.show()

        trayMenu = QMenu()
        trayMenu.addAction('最大化', self.showMaximized)
        trayMenu.addAction('最小化', self.showMinimized)
        trayMenu.addAction('显示窗口', self.showNormal)
        stayOnTop = QAction('总在最前',
                            trayMenu,
                            checkable=True,
                            triggered=self.stayOnTop)
        trayMenu.addAction(stayOnTop)
        trayMenu.addSeparator()
        trayMenu.addAction('退出', QApplication.quit)

        username = platform.node()
        ip = socket.gethostbyname(socket.gethostname())

        self.systray.setToolTip('用户:{}\nIP:{}'.format(username, ip))
        self.systray.activated.connect(self.onSystemTrayActivated)
        self.systray.setContextMenu(trayMenu)

    def onSystemTrayActivated(self, reason):
        if reason in [QSystemTrayIcon.DoubleClick, QSystemTrayIcon.Trigger]:
            self.showNormal()

    def stayOnTop(self, checked):
        self.setWindowFlag(Qt.WindowStaysOnTopHint, self.sender().isChecked())
        self.show()

    def onApplicationQuit(self):
        Config.QSETTING.setValue('MainWindow/geometry', self.saveGeometry())
        Config.QSETTING.setValue('MainWindow/CenterWidget/state',
                                 self.spliter.saveState())
        Config.finalize()
        self.systray.deleteLater()

    def closeEvent(self, event):
        Config.QSETTING.setValue('MainWindow/geometry', self.saveGeometry())
        Config.QSETTING.setValue('MainWindow/CenterWidget/state',
                                 self.spliter.saveState())

        if self.systray.isVisible():
            self.hide()
            event.ignore()
class MyApp(QMainWindow):
    def __init__(self):
        super().__init__()
        print("ready MainWindow")
        self.initUI()
        self.is_pypresence_client_set = False
        self.p = Help()
        self.loadFile()

    #pyqt 종료 이벤트 override 됨
    def closeEvent(self, event):
        if self.is_pypresence_client_set:
            self.RPC.close()
            print("RPC setup done, close event done")
        else:
            print("RPC setup not done, close event done")
            print("check line empty:" + str(self.checkEmptyLine()))
        self.saveFile()
        self.p.close()

    def run_pypresence(self, *args):
        print("run pypresence : " + str(args))
        #pypresence 첫 실행 시
        #pypresence 주어진 client_id로 연결하고 상태를 업데이트
        if not self.is_pypresence_client_set:
            self.client_id = args[0]  #get Discord Developer Portal
            self.RPC = Presence(self.client_id, pipe=0)
            self.RPC.connect()
            self.is_pypresence_client_set = True
            startTime = datetime.datetime.today().timestamp()
            self.RPC.update(details=args[1],
                            state=args[2],
                            large_image=args[3],
                            start=startTime)
        #pypresence 첫 실행이 아닐 시 연결에 변화 없이 내용 업데이트
        elif self.is_pypresence_client_set:
            startTime = datetime.datetime.today().timestamp()
            self.RPC.update(details=args[1],
                            state=args[2],
                            large_image=args[3],
                            start=startTime)

    def initUI(self):
        #Get Foreground Window process name
        w = win32gui
        w.GetWindowText(w.GetForegroundWindow())
        pid = win32process.GetWindowThreadProcessId(w.GetForegroundWindow())
        print(psutil.Process(pid[-1]).name())
        #foreground 프로세스 변경 시 자동으로 사용자 상태가 현재 활성화 된 창을 표시할 수 있도록
        #SetWinEventHook 를 사용하여 foreground프로세스가 변경될 때 이벤트를 받을 수 있어야야함

        #메뉴바 액션
        exitAction = QAction('종료', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('프로그램 종료')
        exitAction.triggered.connect(qApp.quit)

        aboutAction = QAction('제작자', self)
        aboutAction.setStatusTip('제작자의 정보 : iro_bound')
        #exitAction.triggered.connect()

        #스테이터스 바
        #첫번째 호출 시 statusbar 생성, 이후 호출시 상태바 객체 반환
        #showMessage(str) 로 상태 메세지 변경
        self.statusBar().showMessage('DCGA 준비됨')

        #메뉴 바
        #--self.tray icon--
        self.tray = QSystemTrayIcon(QIcon('icon.png'), parent=self)
        self.tray.setToolTip("check out this app on self.tray icon")
        self.tray.setVisible(True)
        menubar = self.menuBar()
        menubar.setNativeMenuBar(False)  #Mac OS sync
        menu = QMenu('&도움말')
        filemenu = menu
        self.tray.setContextMenu(menu)
        filemenu.addAction(exitAction)
        filemenu.addAction(aboutAction)
        menubar.addMenu(menu)

        #센트럴 위젯
        central = QWidget()
        #central.setStyleSheet("background-color:#333333; border-style:solid; border-width: 1px; border-color: #555555; border-radius: 4px;")

        self.idLine = QLineEdit()
        self.idLine.setPlaceholderText("Client ID를 입력")
        self.contentLine = QLineEdit()
        self.contentLine.setPlaceholderText("원하는 내용을 입력")
        self.statusLine = QLineEdit()
        self.statusLine.setPlaceholderText("원하는 상태를 입력")
        self.imageLine = QLineEdit()
        self.imageLine.setPlaceholderText("이미지 이름")
        self.okButton = QPushButton("적용")
        self.okButton.setSizePolicy(QSizePolicy.Expanding,
                                    QSizePolicy.Expanding)
        self.doingButton = QPushButton("설정하기")

        labelID = QLabel("Client 설정 :")
        labelID.setAlignment(Qt.AlignCenter)
        label0 = QLabel("~하는 중 :")
        label0.setAlignment(Qt.AlignCenter)
        label1 = QLabel("내용 : ")
        label1.setAlignment(Qt.AlignCenter)
        label2 = QLabel("상태 : ")
        label2.setAlignment(Qt.AlignCenter)
        label3 = QLabel("이미지 : ")
        label3.setAlignment(Qt.AlignCenter)

        grid = QGridLayout()
        grid.setContentsMargins(59, 50, 50, 50)

        grid.addWidget(labelID, 0, 0)
        grid.addWidget(self.idLine, 0, 1)
        grid.addWidget(label0, 1, 0)
        grid.addWidget(self.doingButton, 1, 1)
        grid.addWidget(label1, 2, 0)
        grid.addWidget(self.contentLine, 2, 1)
        grid.addWidget(label2, 3, 0)
        grid.addWidget(self.statusLine, 3, 1)
        grid.addWidget(label3, 4, 0)
        grid.addWidget(self.imageLine, 4, 1)
        grid.addWidget(self.okButton, 5, 0, 1, 2)

        temp = QPushButton("temp")
        grid.addWidget(temp, 6, 0, 1, 2)
        temp.clicked.connect(self.temms)

        #grid.setColumnStretch(0, 2)
        #grid.setColumnStretch(1, 2)

        central.setLayout(grid)
        self.setCentralWidget(central)

        #윈도우 기본 셋
        self.setWindowTitle('Discord Custom GameActivity')
        self.setWindowIcon(QIcon('icon.png'))
        self.resize(400, 300)

        #self.setWindowFlags(Qt.FramelessWindowHint) #window frame hide
        #self.setAttribute(Qt.WA_TranslucentBackground) #remove border top side grabage
        self.center()
        self.show()
        #self.setStyleSheet("background-color: #333333;") #self -> style css type

        #이벤트
        self.doingButton.clicked.connect(self.onDoingButton)
        self.okButton.clicked.connect(self.onOkButton)
        #self.tray.activated(self.self.trayActiviy(self.tray))

    #화면 창을 가운데로 정렬
    def center(self):
        qr = self.frameGeometry()  #get 창의 위치, 크기 정보를
        cp = QDesktopWidget().availableGeometry().center(
        )  #get 현재 모니터 화면의 가운데 위치
        qr.moveCenter(cp)  #qr에 담긴 프로그램 창의 중심정보를 화면의 중심으로 이동
        self.move(qr.topLeft()
                  )  #현재 창을 qr의 위치로 실제로 이동시킴, 의미 : topLeft => 모니터의 좌상단을 기준으로

    #액션
    def onDoingButton(self):
        webbrowser.open("https://discord.com/developers/applications")
        self.p.show()

    def onOkButton(self):
        id = self.idLine.text()
        content = self.contentLine.text()
        status = self.statusLine.text()
        image = self.imageLine.text()
        print(id, content, status, image)

        if self.checkEmptyLine():
            print("Enter onOkButton event -> checkEmptyLine False Enter here")
            x = QMessageBox.question(self, '경고', '입력 항목을 다시 확인해주세요',
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        else:
            self.run_pypresence(id, content, status, image)

    def checkEmptyLine(self):
        check = True
        if self.idLine.text() == "" or self.contentLine.text(
        ) == "" or self.statusLine.text() == "" or self.imageLine.text() == "":
            check = True
        else:
            check = False
        return check

    def loadFile(self):
        loadContent = './config.json'
        if os.path.isfile(loadContent):
            with open("config.json", "r") as f:
                readfile = json.load(f)
                self.idLine.setText(readfile[0])
                self.contentLine.setText(readfile[1])
                self.statusLine.setText(readfile[2])
                self.imageLine.setText(readfile[3])
                print("file load success")
                print(readfile)
        else:
            print("file load fail")

    def saveFile(self):
        if self.checkEmptyLine():
            print("file save file. check line edit is empty line.")
        else:
            writeContent = [
                self.idLine.text(),
                self.contentLine.text(),
                self.statusLine.text(),
                self.imageLine.text()
            ]
            with open("config.json", "w") as json_file:
                json.dump(writeContent, json_file)
                print("file save success")
                print(writeContent)

    def temms(self):
        if self.tray.isVisible():
            self.tray.setVisible(False)
        elif not self.tray.isVisible():
            self.tray.setVisible(True)
        else:
            print("error")
Beispiel #13
0
class MainWindow(QMainWindow):
    settings_button_clicked = pyqtSignal()
    status_table_clicked = pyqtSignal(str)
    export_accounting = pyqtSignal(str, str, str)


    def __init__(self):
        # Init the base class
        QMainWindow.__init__(self)

        self._settings = load_settings(Config.DEFAULT_SETTINGS)

        # Init the processed .ui file
        self._ui = Ui_MainWindow()
        self._ui.setupUi(self)
        self.setWindowTitle("TradeSkillMaster Application r{}".format(Config.CURRENT_VERSION))

        # connect signals / slots
        self._ui.addon_status_table.doubleClicked.connect(self._addon_status_table_clicked)
        self._ui.backup_status_table.doubleClicked.connect(self._backup_status_table_clicked)
        self._ui.settings_button.clicked.connect(self.settings_button_clicked.emit)
        self._ui.accounts_dropdown.activated['QString'].connect(self.accounts_dropdown_changed)
        self._ui.realm_dropdown.activated['QString'].connect(self.realm_dropdown_changed)
        self._ui.export_button.clicked.connect(self.export_button_clicked)
        self._ui.help_button.setProperty("url", "http://tradeskillmaster.com/site/getting-help")
        self._ui.help_button.clicked.connect(self._link_button_clicked)
        self._ui.premium_button.setProperty("url", "http://tradeskillmaster.com/premium")
        self._ui.premium_button.clicked.connect(self._link_button_clicked)
        self._ui.logo_button.setProperty("url", "http://tradeskillmaster.com")
        self._ui.logo_button.clicked.connect(self._link_button_clicked)
        self._ui.twitter_button.setProperty("url", "http://twitter.com/TSMAddon")
        self._ui.twitter_button.clicked.connect(self._link_button_clicked)

        # Apply the stylesheet
        file = QFile(":/resources/main_window.css")
        file.open(QIODevice.ReadOnly)
        data = str(file.readAll(), encoding="ascii")
        self.setStyleSheet(data)

        # set properties which are necessary for tweaking the style
        self._ui.help_button.setProperty("id", "premiumButton")
        self._ui.premium_button.setProperty("id", "premiumButton")
        self._ui.header_text.setProperty("id", "headerText")

        # stylesheet tweaks for things which don't work when put into the .css for some unknown reason
        self._ui.accounting_tab.setStyleSheet("QCheckBox:disabled { color : #666; } QCheckBox { color : white; }");

        self._sync_status_table_model = TableModel(self, ['Region/Realm', 'AuctionDB', 'Great Deals', 'Last Updated'])
        self._ui.sync_status_table.setModel(self._sync_status_table_model)

        self._addon_status_table_model = TableModel(self, ['Name', 'Version', 'Status'])
        self._ui.addon_status_table.setModel(self._addon_status_table_model)

        self._backup_status_table_model = TableModel(self, ['System ID', 'Account', 'Timestamp', 'Sync Status'])
        self._ui.backup_status_table.setModel(self._backup_status_table_model)

        self._accounting_info = {}
        self._accounting_current_account = ""
        self._accounting_current_realm = ""

        if Config.IS_WINDOWS:
            # create the system tray icon / menu
            self._tray_icon = QSystemTrayIcon(QIcon(":/resources/logo.png"), self)
            self._tray_icon.setToolTip("TradeSkillMaster Application r{}".format(Config.CURRENT_VERSION))
            self._tray_icon.activated.connect(self._icon_activated)
            tray_icon_menu = QMenu(self)
            restore_action = QAction("Restore", tray_icon_menu)
            restore_action.triggered.connect(self._restore_from_tray)
            tray_icon_menu.addAction(restore_action)
            tray_icon_menu.addSeparator()
            quit_action = QAction("Quit", tray_icon_menu)
            quit_action.triggered.connect(self.close)
            tray_icon_menu.addAction(quit_action)
            self._tray_icon.setContextMenu(tray_icon_menu)
            self._tray_icon.hide()


    def __del__(self):
        if Config.IS_WINDOWS:
            self._tray_icon.hide()


    def changeEvent(self, event):
        if not Config.IS_WINDOWS:
            return
        if event.type() == QEvent.WindowStateChange:
            if self.isMinimized() and self._settings.minimize_to_tray:
                logging.getLogger().info("Minimizing to the system tray")
                self._tray_icon.show()
                self.hide()
                event.ignore()


    def closeEvent(self, event):
        if self._settings.confirm_exit:
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QIcon(":/resources/logo.png"))
            msg_box.setWindowModality(Qt.ApplicationModal)
            msg_box.setIcon(QMessageBox.Information)
            msg_box.setText("Are you sure you want to exit?")
            msg_box.setStandardButtons(QMessageBox.Cancel | QMessageBox.Yes)
            if msg_box.exec_() != QMessageBox.Yes:
                event.ignore()
                return
        event.accept()


    def set_visible(self, visible):
        self.setVisible(visible)
        if self._settings.start_minimized and Config.IS_WINDOWS:
            self.showMinimized()
            self.setWindowState(Qt.WindowMinimized)
            if self._settings.minimize_to_tray:
                logging.getLogger().info("Minimizing to the system tray")
                self._tray_icon.show()
                self.hide()
            else:
                logging.getLogger().info("Minimizing")


    def _restore_from_tray(self):
        if not Config.IS_WINDOWS:
            return
        logging.getLogger().info("Restoring from the system tray")
        self.show()
        self.setWindowState(Qt.WindowActive)
        self._tray_icon.hide()


    def _icon_activated(self, reason):
        if not Config.IS_WINDOWS:
            return
        if reason == QSystemTrayIcon.Trigger or reason == QSystemTrayIcon.DoubleClick:
            self._restore_from_tray()


    def _link_button_clicked(self):
        QDesktopServices.openUrl(QUrl(self.sender().property("url")))


    def _addon_status_table_clicked(self, index):
        key = self._addon_status_table_model.get_click_key(index)
        if key:
            self.status_table_clicked.emit(key)


    def _backup_status_table_clicked(self, index):
        key = self._backup_status_table_model.get_click_key(index)
        if key:
            self.status_table_clicked.emit(key)


    def set_sync_status_data(self, data):
        self._sync_status_table_model.set_info(data)
        self._ui.sync_status_table.resizeColumnsToContents()
        self._ui.sync_status_table.sortByColumn(0, Qt.AscendingOrder)


    def set_addon_status_data(self, data):
        self._addon_status_table_model.set_info(data)
        self._ui.addon_status_table.resizeColumnsToContents()
        self._ui.addon_status_table.sortByColumn(0, Qt.AscendingOrder)


    def set_backup_status_data(self, data):
        system_text = "The system ID is unique to the computer you are running the desktop app from. " \
                      "<a href=\"http://tradeskillmaster.com/user/backups\" style=\"color: #EC7800\">Premium users " \
                      "can sync backups</a> to the cloud and across multiple computers. Otherwise, only backups from " \
                      "the local system (<font style=\"color: cyan\">{}</font>) will be listed below.<br><br>To " \
                      "restore a backup, double-click on the row in the table below.".format(Config.SYSTEM_ID)
        self._ui.backup_system_text.setText(system_text)
        self._backup_status_table_model.set_info(data)
        self._ui.backup_status_table.resizeColumnsToContents()
        self._ui.backup_status_table.sortByColumn(2, Qt.DescendingOrder)


    def show_notification(self, message, critical):
        if not Config.IS_WINDOWS:
            return
        icon = QSystemTrayIcon.Critical if critical else QSystemTrayIcon.NoIcon
        if self._tray_icon.isVisible():
            self._tray_icon.showMessage("TradeSkillMaster Desktop Application", message, icon)
        else:
            # The tray icon needs to be visible to show the message, but we can immediately hide it afterwards
            # This is the behavior on Windows 10 at least...need to confirm on other operating systems
            self._tray_icon.show()
            self._tray_icon.showMessage("TradeSkillMaster Desktop Application", message, icon)
            self._tray_icon.hide()


    def _update_dropdown(self, dropdown, items, selected_item):
        items = [""] + items
        selected_index = 0
        dropdown.clear()
        for index, item in enumerate(items):
            if item == selected_item:
                selected_index = index
            dropdown.addItem(item)
        dropdown.setCurrentIndex(selected_index)


    def _update_accounting_tab(self):
        # update the accounts dropdown
        accounts = [x for x in self._accounting_info if self._accounting_info[x]]
        self._update_dropdown(self._ui.accounts_dropdown, accounts, self._accounting_current_account)

        # update the realm dropdown
        self._ui.realm_dropdown.setEnabled(self._accounting_current_account != "")
        if self._accounting_current_account != "":
            self._update_dropdown(self._ui.realm_dropdown,
                                  self._accounting_info[self._accounting_current_account],
                                  self._accounting_current_realm)

        # update the export button
        self._ui.export_button.setEnabled(self._accounting_current_realm != "")


    def set_accounting_accounts(self, info):
        self._accounting_info = info
        self._update_accounting_tab()


    def accounts_dropdown_changed(self, account):
        self._accounting_current_account = account
        self._accounting_current_realm = ""
        self._update_accounting_tab()


    def realm_dropdown_changed(self, realm):
        assert(self._accounting_current_account)
        self._accounting_current_realm = realm
        self._update_accounting_tab()


    def export_button_clicked(self):
        self._ui.export_button.setEnabled(False)
        self._ui.export_button.setText("Exporting...")
        def do_export():
            if self._ui.sales_checkbox.checkState():
                self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "sales")
            if self._ui.purchases_checkbox.checkState():
                self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "purchases")
            if self._ui.income_checkbox.checkState():
                self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "income")
            if self._ui.expenses_checkbox.checkState():
                self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "expenses")
            if self._ui.expired_checkbox.checkState():
                self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "expired")
            if self._ui.canceled_checkbox.checkState():
                self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "canceled")
            self._ui.export_button.setEnabled(True)
            self._ui.export_button.setText("Export to CSV")

            # show a popup saying we've exported everything
            msg_box = QMessageBox()
            msg_box.setWindowIcon(QIcon(":/resources/logo.png"))
            msg_box.setWindowModality(Qt.ApplicationModal)
            msg_box.setIcon(QMessageBox.Information)
            msg_box.setText("The TSM_Accounting data has been successfully exported to your desktop.")
            msg_box.setStandardButtons(QMessageBox.Ok)
            msg_box.exec_()
        # slight delay so the button gets disabled
        QTimer.singleShot(1, do_export)
Beispiel #14
0
class Dialog(QDialog):
  def __init__(self):
    super().__init__()
    # Создание парсера
    self._dotaParser = parser.DotaParser()
    # Инициализация GUI
    self.initUi()
    self.initTray()
    self.initTimer()
    # Первоначальный парсинг
    self.startParser()
    self.fillDialog()
    
  def initUi(self):
    self._ongoingTitle = QLabel("<h3>Ongoing matches</h3>")
    self._ongoingLabel = QLabel("")
    self._upcomingTitle = QLabel("<h3>Upcoming matches</h3>")
    self._upcomingLabel = QLabel("")
    self._quitButton = QPushButton("Quit")
    
    self._layout = QVBoxLayout()
    self._layout.addWidget(self._ongoingTitle)
    self._layout.addWidget(self._ongoingLabel)
    self._layout.addWidget(self._upcomingTitle)
    self._layout.addWidget(self._upcomingLabel)
    self._layout.addWidget(self._quitButton)
    self.setLayout(self._layout)
    
    self._quitButton.clicked.connect(qApp.quit)
    self.setWindowTitle("Dota-2-Widget")
    
  def initTray(self):
    self._tray = QSystemTrayIcon()
    self._tray.setToolTip("dota-2-widget")
    self._tray.setIcon(QIcon("./dota2.gif"))
    self._tray.activated.connect(self.showOrHideDialog)
    self._tray.show()
    
  def initTimer(self):
    self._timer = QTimer()
    self._timer.timeout.connect(self.startParser)
    self._timer.timeout.connect(self.fillDialog)
    self._timer.start(5000)
    
  def startParser(self):
    self._dotaParser.startParser()
    #print("startParser")
    
  def fillDialog(self):
    # Получение результатов
    ongoingMatches = self._dotaParser.getOngoingMatches()
    upcomingMatches = self._dotaParser.getUpcomingMatches()
    # Запись результатов
    resultString = ""
    for i in range(0, len(ongoingMatches)):
      resultString += ongoingMatches[i] + '\n'
    self._ongoingLabel.setText(resultString)
    
    resultString = ""
    for i in range(0, len(upcomingMatches)):
      resultString += upcomingMatches[i] + '\n'
      if (i > 10):
        break
    self._upcomingLabel.setText(resultString)
    #print("fillDialog")
    
  def closeEvent(self, ce):
    if (self._tray.isVisible()):
      self.hide()
      
  def showOrHideDialog(self, result):
    if (result == QSystemTrayIcon.Trigger):
      if (not self.isVisible()):
        self.show()
      else:
        self.hide()
Beispiel #15
0
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(QMainWindow, self).__init__()
        # Set up the user interface from Designer.
        self.setupUi(self)
        
        self.setAccessibleName("Hive Desktop")
        self.redrawLock = Lock()
        self.updateLock = Lock()
        
        self.optionsDialog = dialogs.Options(self)
        self.aboutDialog = dialogs.About(self,
            copyright='holger80',
            programName='Hive Desktop',
            version=VERSION,
            website='https://github.com/holgern/hivedesktop',
            websiteLabel='Github',
            comments='"Welcome to Hive desktop!\n This is the first release for testing qt5.\n Please vote for holger80 as witness, if you like this :).',
            licenseName='GPL-3.0',
            # licenseUrl=helpers.joinpath_to_cwd('LICENSE').as_uri(),
            authors=('holger80',),
            # dependencies=[l.strip() for l in requirements.readlines()],
        )		
        self.mdrenderer = MDRenderer(str(helpers.joinpath_to_cwd('themes')))

        # tmpfile = helpers.mktemp(prefix='hivedesktop', suffix='.html')
        
        self.post = {"body": "##test", "authorperm": "@test/test"}
        self.thread = threads.MDThread(self)
        
        
        # self.webview.url = tmpfile.as_uri()
        
        
        self.feedListWidget.currentRowChanged.connect(self.change_displayed_post, Qt.QueuedConnection)
        
        self.timer = QTimer()
        self.timer.timeout.connect(self.refresh_account_thread)
        
        self.timer2 = QTimer()
        self.timer2.timeout.connect(self.update_account_hist_thread)

        self.timer3 = QTimer()
        self.timer3.timeout.connect(self.update_account_feed_thread)
        
        self.cache_path = QStandardPaths.writableLocation(QStandardPaths.CacheLocation)
        self.db_type = "shelve"
        self.db_type = "sqlite"
        self.feed = []
        self.post = None
        # Get settings
        settings = QSettings()
        # Get checkbox state with speciying type of checkbox:
        # type=bool is a replacement of toBool() in PyQt5
        check_state = settings.value(SETTINGS_TRAY, True, type=bool)
        hist_info_check_state = settings.value(SETTINGS_HIST_INFO, True, type=bool)
        account_state = settings.value(SETTINGS_ACCOUNT, "", type=str)
        self.resize(settings.value(SETTINGS_SIZE, QSize(1053, 800)))
        self.move(settings.value(SETTINGS_POS, QPoint(50, 50)))
        
        #self.accountHistTableWidget.setColumnCount(5)
        #self.accountHistTableWidget.setHorizontalHeaderLabels(["type", "1", "2", "3", "timestamp"])
        
        self.update_account_refreshtime = 5000
        
        # Set state
        self.accountHistNotificationCheckBox.setChecked(hist_info_check_state)
        self.autoRefreshCheckBox.setChecked(check_state)
        if check_state:
            self.timer.start(self.update_account_refreshtime)
            self.timer2.start(15000)
            self.timer3.start(60000)
        self.accountLineEdit.setText(account_state)
        # connect the slot to the signal by clicking the checkbox to save the state settings
        self.autoRefreshCheckBox.clicked.connect(self.save_check_box_settings)   
        self.accountHistNotificationCheckBox.clicked.connect(self.save_check_box_settings)  
        self.accountLineEdit.editingFinished.connect(self.save_account_settings)
        self.actionAbout.triggered.connect(self.about)
        self.actionOptions.triggered.connect(self.options)
        self.threadpool = QThreadPool()
        
        self.minimizeAction = QAction("Mi&nimize", self, triggered=self.hide)
        self.maximizeAction = QAction("Ma&ximize", self,
                triggered=self.showMaximized)
        self.restoreAction = QAction("&Restore", self,
                triggered=self.showNormal)        
        
        menu = QMenu()
        menu.addAction(self.minimizeAction)
        menu.addAction(self.maximizeAction)
        menu.addAction(self.restoreAction)
        menu.addSeparator()        
        # aboutAction = menu.addAction("about")
        # aboutAction.triggered.connect(self.about)
        exitAction = menu.addAction("Exit")
        exitAction.triggered.connect(self.closeApp)
        
        self.tray = QSystemTrayIcon(QIcon(':/icons/icon.ico'))
        
        self.tray.setContextMenu(menu)
        self.tray.activated.connect(self.trayAction)
        
        self.tray.setToolTip("Hive Desktop!")
        self.tray.setObjectName("Hive Desktop")
        self.setWindowTitle("Hive Desktop")
        self.tray.show()
        
        splash_pix = QPixmap(':/icons/splash.png')
        splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
        splash.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
        splash.setEnabled(False)
        
        #splash.show()
        #splash.showMessage("<h1><font color='green'>starting...</font></h1>", Qt.AlignTop | Qt.AlignCenter, Qt.black)        
        
        account = account_state
        nodelist = NodeList()
        nodelist.update_nodes()
        self.stm = Steem(node=nodelist.get_nodes(hive=True))
        set_shared_blockchain_instance(self.stm)
        if account != "":
            try:
                self.hist_account = Account(account, steem_instance=self.stm)
            except:
                self.hist_account = None
        else:
            self.hist_account = None
            
        self.refreshPushButton.clicked.connect(self.refresh_account)
        self.refreshPushButton.clicked.connect(self.update_account_hist_thread)
        self.accountLineEdit.editingFinished.connect(self.update_account_info)        
        if self.hasFocus is not None:
            self.init_new_account()
            self.init_new_blocks()
        splash.deleteLater()

    def triggeredPreview(self):
        self.authorLabel.setText(self.post["author"])
        self.titleLabel.setText(self.post["title"])
        self.auhorpermLineEdit.setText(construct_authorperm(self.post["author"], self.post["permlink"]))
        self.thread.start()

    @pyqtSlot(str)
    def cbMDThread(self, html):
        self.webview.setHtml(html)

    @pyqtSlot(QSystemTrayIcon.ActivationReason)
    def trayAction(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            if self.isHidden():
                self.showNormal()
            else:
                self.hide()

    def closeEvent(self, event):
        if self.tray.isVisible():
            #QMessageBox.information(self, "Hive Desktop",
            #        "The program will keep running in the system tray. To "
            #        "terminate the program, choose <b>Quit</b> in the "
            #        "context menu of the system tray entry.")
            self.tray.showMessage("Hive Desktop",
                    "The program will keep running in the system tray. To "
                    "terminate the program, choose Quit in the "
                    "context menu of the system tray entry.")           
            self.hide()
            event.ignore()

    def hide(self):
        self.update_account_refreshtime = 60000
        self.timer.start(self.update_account_refreshtime)
        QMainWindow.hide(self)
        

    def showNormal(self):
        self.update_account_refreshtime = 5000
        self.timer.start(self.update_account_refreshtime)
        QMainWindow.showNormal(self)

    def showMaximized(self):
        self.update_account_refreshtime = 5000
        self.timer.start(self.update_account_refreshtime)
        QMainWindow.showMaximized(self)

    def closeApp(self):
        settings = QSettings()
        settings.setValue(SETTINGS_SIZE, self.size())
        settings.setValue(SETTINGS_POS, self.pos())
        settings.sync()
        sys.exit()

    def about(self):
        self.aboutDialog.exec_()

    def options(self):
        self.optionsDialog.exec_()

    # Slot checkbox to save the settings
    def save_check_box_settings(self):
        settings = QSettings()
        settings.setValue(SETTINGS_HIST_INFO, self.accountHistNotificationCheckBox.isChecked())
        settings.setValue(SETTINGS_TRAY, self.autoRefreshCheckBox.isChecked())
        if self.autoRefreshCheckBox.isChecked():
            self.timer.start(self.update_account_refreshtime)
            self.timer2.start(15000)
            self.timer3.start(60000)
        else:
            self.timer.stop()
            self.timer2.stop()
            self.timer3.stop()
        settings.sync()

    # Slot checkbox to save the settings
    def save_account_settings(self):
        settings = QSettings()
        settings.setValue(SETTINGS_ACCOUNT, self.accountLineEdit.text())
        settings.sync()

    def update_account_info(self):
        if self.hist_account is None or self.hist_account["name"] != self.accountLineEdit.text():
            try:
                self.hist_account = Account(self.accountLineEdit.text(), steem_instance=self.stm)
            except:
                self.hist_account = None
            self.init_new_account()

    def init_new_account(self):
        self.refresh_account()
        self.update_account_feed()
        if self.hist_account is not None:
            self.db = database.Database(self.db_type, self.cache_path, self.hist_account["name"])
            self.loadingProgressBar.setMaximum(self.db.get_account().virtual_op_count())
            self.iah_thread = threads.IAHThread(self, self.db)
            self.timer.stop()
            self.timer2.stop()
            self.refreshPushButton.setEnabled(False)
            self.accountLineEdit.setEnabled(False)            
            self.iah_thread.start()
        else:
            self.init_account_hist()
            self.update_account_hist()

    def init_new_blocks(self):
        blockchain = Blockchain()
        self.block_db = database_blocks.DatabaseBlocks(self.db_type, self.cache_path)
        self.loadingBlocksProgressBar.setMaximum(self.block_db.block_history)
        self.blocks_thread = threads.BlocksThread(self, self.block_db, blockchain)
        self.blocks_thread.start()

    @pyqtSlot(str)
    def cIAHThread(self, dummy):
        self.init_account_hist()
        self.update_account_hist()
        self.refreshPushButton.setEnabled(True)
        self.accountLineEdit.setEnabled(True)
        self.tray.showMessage("Ready", "Account history loaded!")     
        self.timer.start(self.update_account_refreshtime)
        self.timer2.start(15000)

    @pyqtSlot(str)
    def cBlocksThread(self, dummy):
        self.init_blocks()
        self.update_blocks()
           
        #self.timer.start(self.update_account_refreshtime)
        #self.timer2.start(15000)

    def refresh_account_thread(self):
        worker = Worker(self.refresh_account)
        self.threadpool.start(worker)        

    def refresh_account(self):
        if self.hist_account is None:
            return
        self.hist_account.refresh()
        self.accountInfoGroupBox.setTitle("%s (%.3f)" % (self.hist_account["name"], self.hist_account.rep))
        with self.redrawLock:
            self.votePowerProgressBar.setValue(int(self.hist_account.vp))
            if self.hist_account.vp == 100:
                self.votePowerProgressBar.setFormat("%.2f %%" % (self.hist_account.vp))
            else:
                self.votePowerProgressBar.setFormat("%.2f %%, full in %s" % (self.hist_account.vp, self.hist_account.get_recharge_time_str()))
        down_vp = self.hist_account.get_downvoting_power()
        with self.redrawLock:
            self.downvotePowerProgressBar.setValue(int(down_vp))
            if down_vp == 100:
                self.downvotePowerProgressBar.setFormat("%.2f %%" % (down_vp))
            else:
                self.downvotePowerProgressBar.setFormat("%.2f %%, full in %s" % (down_vp, self.hist_account.get_recharge_time(starting_voting_power=down_vp)))
        
        self.votePowerLabel.setText("Vote Power, a 100%% vote is %.3f $" % (self.hist_account.get_voting_value_SBD()))
        self.downvotePowerLabel.setText("DownVote Power")
        self.STEEMLabel.setText(str(self.hist_account["balance"]))
        self.SBDLabel.setText(str(self.hist_account["sbd_balance"]))
        self.SPLabel.setText("%.3f HP" % self.stm.vests_to_sp(self.hist_account["vesting_shares"]))
        try:
            rc_manabar = self.hist_account.get_rc_manabar()
            with self.redrawLock:
                self.RCProgressBar.setValue(int(rc_manabar["current_pct"]))
                self.RCProgressBar.setFormat("%.2f %%, full in %s" % (rc_manabar["current_pct"], self.hist_account.get_manabar_recharge_time_str(rc_manabar)))
        
            rc = self.hist_account.get_rc()
            estimated_rc = int(rc["max_rc"]) * rc_manabar["current_pct"] / 100
            rc_calc = RC(steem_instance=self.stm)
            self.RCLabel.setText("RC (%.0f G RC of %.0f G RC)" % (estimated_rc / 10**9, int(rc["max_rc"]) / 10**9))
            ret = "--- Approx Costs ---\n"
            ret += "comment - %.2f G RC - enough RC for %d comments\n" % (rc_calc.comment() / 10**9, int(estimated_rc / rc_calc.comment()))
            ret += "vote - %.2f G RC - enough RC for %d votes\n" % (rc_calc.vote() / 10**9, int(estimated_rc / rc_calc.vote()))
            ret += "transfer - %.2f G RC - enough RC for %d transfers\n" % (rc_calc.transfer() / 10**9, int(estimated_rc / rc_calc.transfer()))
            ret += "custom_json - %.2f G RC - enough RC for %d custom_json\n" % (rc_calc.custom_json() / 10**9, int(estimated_rc / rc_calc.custom_json()))
            self.text.setText(ret)
        except:
            rc_manabar = None

    @pyqtSlot(int)
    def set_loading_progress(self, val):
        with self.redrawLock:
            self.loadingProgressBar.setValue(val)

    @pyqtSlot(int)
    def set_loading_blocks_progress(self, val):
        with self.redrawLock:
            self.loadingBlocksProgressBar.setValue(val)

    def init_blocks(self):
        self.blockCountLabel.setText("%d entries" % self.block_db.get_block_count())

    def init_account_hist(self):
        if self.hist_account is None:
            return
        self.account_hist_info = {"start_block": 0}
        self.append_hist_info = {"start_block": 0}

        #if not self.db.has_account_hist():
        #    ops = self.db.get_acc_hist()
        #    self.db.store_account_hist(ops)
        #else:
        #    start_op = self.db.get_last_op()
        #    ops = self.db.read_missing_account_history_data(start_op)
        #    self.db.store_account_hist(ops)
        self.accountHistoryLabel.setText("%d entries" % self.db.get_count())
        self.accountHistTableWidget.clear()

    def append_blocks(self):
        start_op = self.block_db.get_last_op()
        data = self.block_db.read_missing_block_data(start_op)
        # print("finished")
        if len(data) > 0:
            # print(op["timestamp"])
            self.block_db.append_blocks(data)
            self.blockCountLabel.setText("%d entries" % self.block_db.get_block_count())        

    def append_account_hist(self):
        if self.hist_account is None:
            return
        
        # print("loading db")
        
        start_op = self.db.get_last_op()
        data = self.db.read_missing_account_history_data(start_op)
        # print("finished")
        if len(data) > 0:
            # print(op["timestamp"])
            self.db.append_account_hist(data)
            self.accountHistoryLabel.setText("%d entries" % self.db.get_count())

    def update_account_hist_thread(self):
        worker = Worker(self.update_account_hist)
        self.threadpool.start(worker)

    def update_account_feed_thread(self):
        worker = Worker(self.update_account_feed)
        self.threadpool.start(worker)

    @pyqtSlot(int)
    def change_displayed_post(self, row):
        if row < 0:
            return
        if len(self.feed) == 0:
            return
        if len(self.feed) <= row:
            return
        #index = self.feedListWidget.currentIndex()
        #row = index.row()
        self.post = self.feed[row]
        with self.updateLock:
            self.triggeredPreview()
        replies = Comment(self.post).get_all_replies()
        is_shown = [0] * len(replies)
        max_depth = 0
        for i in range(len(replies)):
            if replies[i].depth > max_depth:
                max_depth = replies[i].depth
        self.commentsTreeWidget.clear()
        
        def create_item(reply):
            item = QTreeWidgetItem()
            item.setText(0, reply["author"])
            item.setText(1, reply["body"])
            item.setToolTip(1, reply["body"])
            return item

      
        for i in range(len(replies)):
            if is_shown[i] == 1:
                continue
            reply = replies[i]
            if reply.depth == 1:
                is_shown[i] = 1
                item = create_item(reply)
                
                for j in range(len(replies)):
                    rr = replies[j]
                    if is_shown[j] == 1:
                        continue
                    if rr.depth == 2:
                        is_shown[j] = 1
                        if rr.parent_author == reply["author"] and rr.parent_permlink == reply["permlink"]:
                            rr_item = create_item(rr)
                            if max_depth >= 3:
                                for k in range(len(replies)):
                                    rrr = replies[k]
                                    if is_shown[k] == 1:
                                        continue
                                    if rrr.depth == 3:
                                        is_shown[k] = 1
                                        if rrr.parent_author == rr["author"] and rrr.parent_permlink == rr["permlink"]:
                                            rrr_item = create_item(rrr)
                                            if max_depth >= 4:
                                                for l in range(len(replies)):
                                                    rrrr = replies[l]
                                                    if is_shown[l] == 1:
                                                        continue
                                                    if rrrr.depth == 4:
                                                        is_shown[l] = 1
                                                        if rrrr.parent_author == rrr["author"] and rrrr.parent_permlink == rrr["permlink"]:
                                                            rrrr_item = create_item(rrrr)
                                                            rrr_item.addChild(rrrr_item)
                                        
                                        rr_item.addChild(rrr_item)
                            item.addChild(rr_item)
                
                self.commentsTreeWidget.addTopLevelItem(item)

    def update_account_feed(self):
        if self.hist_account is None:
            return
        try:
            updated_feed = self.hist_account.get_account_posts()
        except:
            print("could not update feed")
            return
        if len(self.feed) == 0:
            self.feed = updated_feed
        else:
            for post in updated_feed[::-1]:
                found = False
                for p in self.feed:
                    if post["authorperm"] == p["authorperm"]:
                        found = True
                if not found:
                    self.feed.insert(0, post)
                    if (addTzInfo(datetime.utcnow()) - post["created"]).total_seconds() / 60 < 5:
                        self.tray.showMessage(post["author"], post["title"])
        with self.updateLock:
            if self.post is None:
                self.post = self.feed[0]
                self.triggeredPreview()

            self.feedListWidget.currentRowChanged.disconnect(self.change_displayed_post)
            self.feedListWidget.clear()
            for post in self.feed[::-1]:
                post_text = "%s - %s" % (post["author"], post["title"])
                post_item = QListWidgetItem()
                post_item.setText(post_text)
                post_item.setToolTip(post["author"])
                self.feedListWidget.insertItem(0, post_item)   
            self.feedListWidget.currentRowChanged.connect(self.change_displayed_post, Qt.QueuedConnection)

    def update_blocks(self):
        return

    def update_account_hist(self):
        if self.hist_account is None:
            return        
        votes = []
        daily_curation = 0
        daily_author_SP = 0
        daily_author_SBD = 0
        daily_author_STEEM = 0
        self.append_account_hist()
        
        new_op_found = False
        
        start_block = self.account_hist_info["start_block"]
        if start_block == 0:
            first_call = True
            b = Blockchain()
            start_block = b.get_current_block_num() - 20 * 60 * 24 * 7
            self.account_hist_info["start_block"] = start_block
        else:
            first_call = False

        ops = self.db.load_account_hist(start_block)
     
        for op in ops:
            if op["block"] < start_block:
                # last_block = op["block"]
                continue

            start_block = op["block"]
            new_op_found = True
            tray_item = None
            op_timedelta = formatTimedelta(addTzInfo(datetime.utcnow()) - addTzInfo(op["timestamp"]))
            op_local_time = addTzInfo(op["timestamp"]).astimezone(tz.tzlocal())
            # print("Read %d" % op["index"])
            self.accountHistTableWidget.insertRow(0)
            self.accountHistTableWidget.setItem(0, 4, QTableWidgetItem(str(op_local_time)))
            if op["type"] == "vote":
                
                
                if op["voter"] == self.hist_account["name"]:
                    self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem("Vote"))
                    self.accountHistTableWidget.setItem(0, 1, QTableWidgetItem(op["author"]))
                    
                elif op["weight"] >= 0:
                    self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem("Vote Post"))
                    self.accountHistTableWidget.setItem(0, 1, QTableWidgetItem(op["voter"]))
                    tray_item = "%s - %s (%.2f %%) vote %s" % (op["type"], op["voter"], op["weight"] / 100, op["permlink"])
                else:
                    self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem("Dowvote Post"))
                    self.accountHistTableWidget.setItem(0, 1, QTableWidgetItem(op["voter"]))
                    # hist_item.setToolTip(0, op["permlink"])
                    tray_item = "%s - %s (%.2f %%) downvote %s" % (op["type"], op["voter"], op["weight"] / 100, op["permlink"])
                
                
                self.accountHistTableWidget.setItem(0, 2, QTableWidgetItem("%.2f %%" % (op["weight"] / 100)))
                
            elif op["type"] == "curation_reward":
                self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(op["type"]))
                
                curation_reward = self.stm.vests_to_sp(Amount(op["reward"], steem_instance=self.stm))
                self.accountHistTableWidget.setItem(0, 1, QTableWidgetItem("%.3f HP" % curation_reward))
                self.accountHistTableWidget.setItem(0, 2, QTableWidgetItem(construct_authorperm(op["comment_author"], op["comment_permlink"])))
                hist_item = "%s - %s - %.3f HP for %s" % (op_local_time, op["type"], curation_reward, construct_authorperm(op["comment_author"], op["comment_permlink"]))
                tray_item = "%s - %.3f HP for %s" % (op["type"], curation_reward, construct_authorperm(op["comment_author"], op["comment_permlink"]))
            elif op["type"] == "author_reward":
                self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(op["type"]))
                sbd_payout = (Amount(op["sbd_payout"], steem_instance=self.stm))
                steem_payout = (Amount(op["steem_payout"], steem_instance=self.stm))
                sp_payout = self.stm.vests_to_sp(Amount(op["vesting_payout"], steem_instance=self.stm))
                
                hist_item = "%s - %s - %s %s %.3f SP for %s" % (op_local_time, op["type"], str(sbd_payout), str(steem_payout), sp_payout, op["permlink"])
                tray_item = "%s - %s %s %.3f SP for %s" % (op["type"], str(sbd_payout), str(steem_payout), sp_payout, op["permlink"])
            elif op["type"] == "custom_json":
                self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(op["type"]))
                self.accountHistTableWidget.setItem(0, 1, QTableWidgetItem(op["json_id"]))
                json_data = QTableWidgetItem(op["json"])
                json_data.setToolTip(op["json"])
                self.accountHistTableWidget.setItem(0, 2, json_data)
                hist_item = "%s - %s - %s" % (op_local_time, op["type"], op["id"])
                tray_item = "%s - %s" % (op["type"], op["json_id"])
            elif op["type"] == "transfer":
                self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(op["type"]))
                hist_item = "%s - %s - %s from %s" % (op_local_time, op["type"], str(Amount(op["amount"], steem_instance=self.stm)), op["from"])
                tray_item = "%s - %s from %s" % (op["type"], str(Amount(op["amount"], steem_instance=self.stm)), op["from"])
            elif op["type"] == "comment":
                
                
                if op["parent_author"] != "":
                    comment_type = "comment"
                    hist_item = "%s - comment on %s - %s from %s" % (op_local_time, construct_authorperm(op["parent_author"], op["parent_permlink"]), op["title"], op["author"])
                    tray_item = "comment from %s: %s on %s" % (op["author"], op["body"][:100], op["title"])
                    self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(op["type"]))
                    self.accountHistTableWidget.setItem(0, 1, QTableWidgetItem(op["author"]))
                    body = QTableWidgetItem(op["body"])
                    body.setToolTip(op["body"])
                    self.accountHistTableWidget.setItem(0, 2, body)
                else:
                    comment_type = "post"
                    hist_item = "%s - post - %s from %s" % (op_local_time, op["title"], op["author"])
                    tray_item = "post from %s: %s" % (op["author"], op["title"])
                self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(comment_type))
            elif op["type"] == "producer_reward":
                self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(op["type"]))
                self.accountHistTableWidget.setItem(0, 1, QTableWidgetItem(" %.3f HP" % float(self.stm.vests_to_sp(Amount(op["vesting_shares"])))))
                hist_item = "%s - %s" % (op_local_time, op["type"])
                tray_item = "%s - %.3f HP" % (op["type"], float(self.stm.vests_to_sp(Amount(op["vesting_shares"]))))               
            else:
                self.accountHistTableWidget.setItem(0, 0, QTableWidgetItem(op["type"]))
                hist_item = "%s - %s" % (op_local_time, op["type"])
                tray_item = "%s" % (op["type"])
            
            if self.accountHistNotificationCheckBox.isChecked() and not first_call and tray_item is not None:
                self.tray.showMessage(self.hist_account["name"], tray_item)

        if new_op_found:
            self.account_hist_info["start_block"] = start_block
            
            for op in ops:
                if op["type"] == "vote":
                    if op["voter"] == self.hist_account["name"]:
                        continue
                    votes.append(op)
                elif op["type"] == "curation_reward":
                    curation_reward = self.stm.vests_to_sp(Amount(op["reward"], steem_instance=self.stm))
                    daily_curation += curation_reward
                elif op["type"] == "author_reward":
                    sbd_payout = (Amount(op["sbd_payout"], steem_instance=self.stm))
                    steem_payout = (Amount(op["steem_payout"], steem_instance=self.stm))
                    sp_payout = self.stm.vests_to_sp(Amount(op["vesting_payout"], steem_instance=self.stm))
                    daily_author_SP += sp_payout
                    daily_author_STEEM += float(steem_payout)
                    daily_author_SBD += float(sbd_payout)        
        
            
            reward_text = "Curation reward (last 24 h): %.3f HP\n" % daily_curation
            reward_text += "Author reward (last 24 h):\n"
            reward_text += "%.3f HP - %.3f HIVE - %.3f HBD" % (daily_author_SP, (daily_author_STEEM), (daily_author_SBD))
            self.text2.setText(reward_text)