Ejemplo n.º 1
0
class ErgebnissVorlage(QWidget):
    def __init__(self, parent=None):
        super(ErgebnissVorlage, self).__init__(parent)

        self.auswahlAlter = QComboBox()
        self.auswahlAlter.addItem("Bitte auswählen")
        for i in range(3, 18):
            self.auswahlAlter.addItem("{} Jahre / Jahrgang {}".format(i, date.today().year - i))

        self.auswahlGeschlecht = QComboBox()
        self.auswahlGeschlecht.addItem("Bitte auswählen")
        self.auswahlGeschlecht.addItem("Männlich")
        self.auswahlGeschlecht.addItem("Weiblich")

        self.printerProgress = QProgressBar()
        self.printerProgress.hide()

        self.mainLayout = QFormLayout()
        self.mainLayout.addRow(QLabel("Alter:"),self.auswahlAlter)
        self.mainLayout.addRow(QLabel("Geschlecht:"),self.auswahlGeschlecht)
        self.mainLayout.addRow(self.printerProgress)

        self._drucken = QPushButton("Drucken")
        self._drucken.clicked.connect(self.drucken)

        self.mainLayout.addRow(self._drucken)

        self.setLayout(self.mainLayout)

    def queryUsers(self,Alter:int, Geschlecht:bool)->list:
        return QueryTool().fetchAllByWhere("LG_NGD",WieAlt=Alter,Geschlecht=Geschlecht)

    def drucken(self):
        self.printerProgress.show()

        if (self.auswahlAlter.currentIndex() is 0) and (self.auswahlGeschlecht.currentIndex() is 0):
            Alter = range(3,18)
            Geschlecht = range(0,2)
        else:
            Alter = self.auswahlAlter.currentIndex()+2
            Alter = range(Alter,Alter+1)

            Geschlecht = self.auswahlGeschlecht.currentIndex()-1
            Geschlecht = range(Geschlecht,Geschlecht+1)

        self.printerProgress.setMaximum(len(Alter)*len(Geschlecht)*10)
        self.printerProgress.setValue(0)

        prog = 0

        for a in Alter:
            for g in Geschlecht:
                for d in range(10):
                    ErgebnissVorlagenDrucker(a,g,d)
                    self.printerProgress.setValue(prog)
                    prog +=1
        self.printerProgress.hide()
Ejemplo n.º 2
0
class CpSplashScreen(QSplashScreen):

	def __init__(self, parent = None, pixmap = None, maxSteps = 1):
		super().__init__(parent, pixmap)
		self.maxSteps = maxSteps
		self.progress = QProgressBar(self)
		#self.progress.setGeometry(15, 15, 100, 10)
		self.progress.setTextVisible(False)
		self.progress.setMinimum(0)
		self.progress.setMaximum(self.maxSteps)
		self.progress.setValue(0)
		self.progress.hide()

	def show(self):
		super().show()
		geo = self.geometry()
		self.progress.setGeometry(5, geo.height() - 20, 100, 10)
		self.progress.show()

	def showMessage(self, msg, step = None, color = None):
		if step is not None:
			self.progress.setValue(step)
			self.progress.update()
		super().showMessage(msg, color=color)
class UpdateCheck(QWidget, Logger):
    url = "electrumx.hashexplorer.net"
    download_url = "https://www.omotenashicoin.site/downloads.php"

    VERSION_ANNOUNCEMENT_SIGNING_KEYS = (
        "SSuepd54qhEjZydPPrFAYL5tWHomMyHTQL", )

    def __init__(self, main_window, latest_version=None):
        self.main_window = main_window
        QWidget.__init__(self)
        self.setWindowTitle('Electrum - ' + _('Update Check'))
        self.content = QVBoxLayout()
        self.content.setContentsMargins(*[10] * 4)

        self.heading_label = QLabel()
        self.content.addWidget(self.heading_label)

        self.detail_label = QLabel()
        self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.detail_label.setOpenExternalLinks(True)
        self.content.addWidget(self.detail_label)

        self.pb = QProgressBar()
        self.pb.setMaximum(0)
        self.pb.setMinimum(0)
        self.content.addWidget(self.pb)

        versions = QHBoxLayout()
        versions.addWidget(
            QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION))))
        self.latest_version_label = QLabel(_("Latest version: {}".format(" ")))
        versions.addWidget(self.latest_version_label)
        self.content.addLayout(versions)

        self.update_view(latest_version)

        self.update_check_thread = UpdateCheckThread(self.main_window)
        self.update_check_thread.checked.connect(self.on_version_retrieved)
        self.update_check_thread.failed.connect(self.on_retrieval_failed)
        self.update_check_thread.start()

        close_button = QPushButton(_("Close"))
        close_button.clicked.connect(self.close)
        self.content.addWidget(close_button)
        self.setLayout(self.content)
        self.show()

    def on_version_retrieved(self, version):
        self.update_view(version)

    def on_retrieval_failed(self):
        self.heading_label.setText('<h2>' + _("Update check failed") + '</h2>')
        self.detail_label.setText(
            _("Sorry, but we were unable to check for updates. Please try again later."
              ))
        self.pb.hide()

    @staticmethod
    def is_newer(latest_version):
        return latest_version > StrictVersion(version.ELECTRUM_VERSION)

    def update_view(self, latest_version=None):
        if latest_version:
            self.pb.hide()
            self.latest_version_label.setText(
                _("Latest version: {}".format(latest_version)))
            if self.is_newer(latest_version):
                self.heading_label.setText(
                    '<h2>' + _("There is a new update available") + '</h2>')
                url = "<a href='{u}'>{u}</a>".format(
                    u=UpdateCheck.download_url)
                self.detail_label.setText(
                    _("You can download the new version from {}.").format(url))
            else:
                self.heading_label.setText('<h2>' + _("Already up to date") +
                                           '</h2>')
                self.detail_label.setText(
                    _("You are already on the latest version of Electrum."))
        else:
            self.heading_label.setText('<h2>' + _("Checking for updates...") +
                                       '</h2>')
            self.detail_label.setText(
                _("Please wait while Electrum checks for available updates."))
Ejemplo n.º 4
0
class TabRewards_gui(QWidget):
    def __init__(self, imgDir, *args, **kwargs):
        QWidget.__init__(self)
        self.imgDir = imgDir
        self.initRewardsForm()
        mainVertical = QVBoxLayout()
        mainVertical.addWidget(self.rewardsForm)
        buttonbox = QHBoxLayout()
        buttonbox.addStretch(1)
        buttonbox.addWidget(self.btn_Cancel)
        mainVertical.addLayout(buttonbox)
        self.setLayout(mainVertical)

    def initRewardsForm(self):
        self.collateralHidden = True
        self.rewardsForm = QGroupBox()
        self.rewardsForm.setTitle("Transfer Rewards")
        layout = QFormLayout()
        layout.setContentsMargins(10, 10, 10, 10)
        layout.setSpacing(13)
        layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        ##--- ROW 1
        hBox = QHBoxLayout()
        self.mnSelect = QComboBox()
        self.mnSelect.setToolTip("Select Masternode")
        hBox.addWidget(self.mnSelect)
        self.btn_ReloadUTXOs = QPushButton()
        self.btn_ReloadUTXOs.setToolTip("Reload UTXOs")
        refresh_icon = QIcon(os.path.join(self.imgDir, 'icon_refresh.png'))
        self.btn_ReloadUTXOs.setIcon(refresh_icon)
        hBox.addWidget(self.btn_ReloadUTXOs)
        hBox.addStretch(1)
        label = QLabel("Total Address Balance")
        label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        hBox.addWidget(label)
        self.addrAvailLine = QLabel()
        self.addrAvailLine.setToolTip("PIVX Address total balance")
        self.addrAvailLine.setText("--")
        hBox.addWidget(self.addrAvailLine)
        self.btn_toggleCollateral = QPushButton("Show Collateral")
        hBox.addWidget(self.btn_toggleCollateral)
        layout.addRow(QLabel("Masternode"), hBox)
        ## --- ROW 2: REWARDS
        self.rewardsList = QVBoxLayout()
        self.rewardsList.statusLabel = QLabel()
        self.rewardsList.statusLabel.setMinimumWidth(116)
        self.resetStatusLabel('<b style="color:red">Reload Rewards</b>')
        self.rewardsList.addWidget(self.rewardsList.statusLabel)
        self.rewardsList.box = QTableWidget()
        self.rewardsList.box.setMinimumHeight(140)
        #self.rewardsList.box.setMaximumHeight(140)
        self.rewardsList.box.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.rewardsList.box.setSelectionMode(QAbstractItemView.MultiSelection)
        self.rewardsList.box.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.rewardsList.box.setShowGrid(True)
        self.rewardsList.box.setColumnCount(4)
        self.rewardsList.box.setRowCount(0)
        self.rewardsList.box.horizontalHeader().setSectionResizeMode(
            2, QHeaderView.Stretch)
        self.rewardsList.box.verticalHeader().hide()
        item = QTableWidgetItem()
        item.setText("PIVs")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(0, item)
        item = QTableWidgetItem()
        item.setText("Confirmations")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(1, item)
        item = QTableWidgetItem()
        item.setText("TX Hash")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(2, item)
        item = QTableWidgetItem()
        item.setText("TX Output N")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(3, item)
        item = QTableWidgetItem()
        self.rewardsList.addWidget(self.rewardsList.box)
        layout.addRow(self.rewardsList)
        ##--- ROW 3
        hBox2 = QHBoxLayout()
        self.btn_selectAllRewards = QPushButton("Select All")
        self.btn_selectAllRewards.setToolTip("Select all available UTXOs")
        hBox2.addWidget(self.btn_selectAllRewards)
        self.btn_deselectAllRewards = QPushButton("Deselect all")
        self.btn_deselectAllRewards.setToolTip("Deselect current selection")
        hBox2.addWidget(self.btn_deselectAllRewards)
        hBox2.addWidget(QLabel("Selected rewards"))
        self.selectedRewardsLine = QLabel()
        self.selectedRewardsLine.setMinimumWidth(200)
        self.selectedRewardsLine.setStyleSheet("color: purple")
        self.selectedRewardsLine.setToolTip("PIVX to move away")
        hBox2.addWidget(self.selectedRewardsLine)
        hBox2.addStretch(1)
        self.swiftxCheck = QCheckBox()
        self.swiftxCheck.setToolTip(
            "check for SwiftX instant transaction (flat fee rate of 0.01 PIV)")
        hBox2.addWidget(QLabel("Use SwiftX"))
        hBox2.addWidget(self.swiftxCheck)
        layout.addRow(hBox2)
        ##--- ROW 4
        hBox3 = QHBoxLayout()
        self.destinationLine = QLineEdit()
        self.destinationLine.setToolTip("PIVX address to transfer rewards to")
        hBox3.addWidget(self.destinationLine)
        hBox3.addWidget(QLabel("Fee"))
        self.feeLine = QDoubleSpinBox()
        self.feeLine.setDecimals(8)
        self.feeLine.setPrefix("PIV  ")
        self.feeLine.setToolTip("Insert a small fee amount")
        self.feeLine.setFixedWidth(150)
        self.feeLine.setSingleStep(0.001)
        hBox3.addWidget(self.feeLine)
        self.btn_sendRewards = QPushButton("Send")
        hBox3.addWidget(self.btn_sendRewards)
        layout.addRow(QLabel("Destination Address"), hBox3)
        ##--- ROW 5
        hBox4 = QHBoxLayout()
        hBox4.addStretch(1)
        self.loadingLine = QLabel(
            "<b style='color:red'>Preparing TX.</b> Completed: ")
        self.loadingLinePercent = QProgressBar()
        self.loadingLinePercent.setMaximumWidth(200)
        self.loadingLinePercent.setMaximumHeight(10)
        self.loadingLinePercent.setRange(0, 100)
        hBox4.addWidget(self.loadingLine)
        hBox4.addWidget(self.loadingLinePercent)
        self.loadingLine.hide()
        self.loadingLinePercent.hide()
        layout.addRow(hBox4)
        #--- Set Layout
        self.rewardsForm.setLayout(layout)
        #--- ROW 5
        self.btn_Cancel = QPushButton("Clear/Reload")

    def resetStatusLabel(self, message=None):
        if message is None:
            self.rewardsList.statusLabel.setText(
                '<em><b style="color:purple">Checking explorer...</b></em>')
        else:
            self.rewardsList.statusLabel.setText(message)
        self.rewardsList.statusLabel.setVisible(True)
Ejemplo n.º 5
0
class OvirtClient(QWidget):
    """
        This class will handle the main window where all user's VMs will be listed.
        This will be rendered only if authentication was successfull since it doesn't
        make sense otherwise. Additionally, a Thread will be started checking VM status
        changes and update the board accordingly.
    """

    stopThread = False  # Sentinel for stopping the Thread execution
    autologoutWarn = False  # Has the user been warned about autologout yet?
    openviewer_vms = []  # Initiated VMs in terms of the viewer
    updatesignal = pyqtSignal(
        int, str)  # Signal to update the status icons on status changes
    reloadsignal = pyqtSignal()  # Signal to reload the main widget
    warnlogoutsignal = pyqtSignal(
    )  # Signal to warn the user about an imminent autologout
    logoutsignal = pyqtSignal(
        bool
    )  # Signal to logout the current user and require credentials again
    lastclick = int(time(
    ))  # Timestamp of the last click. If a timeout policy is defined and

    # the time exceeds this value, an autologout will be performed.

    def __init__(self):
        QWidget.__init__(self)
        self.initUI()

    def vm_based_resize(self, vmnum):
        """
            Description: Depending on the number of VMs which the user has permissions on,
                         we need to resize the main window accordingly in height.The fewer
                         they are, the smaller the window will be. If MAXHEIGHT is reached,
                         a scrollbar will also be shown (that's processed in a different
                         place, though)
            Parameters: The number of VMs.
            Returns: The actual window height.
        """

        global MAXHEIGHT

        if not vmnum:
            # If user has no machines, resize window to the minimum
            winheight = 150
            no_machines = QLabel(_('no_vms'))
            no_machines.setWordWrap(True)
            no_machines.setAlignment(Qt.AlignCenter)
            self.grid.addWidget(no_machines, 0, 0)
            self.setMinimumHeight(winheight)
        else:
            # User has at least one VM
            if vmnum > 5:
                # More than 5 means resizing the window to the maximum
                winheight = MAXHEIGHT
                self.setFixedHeight(winheight)
            else:
                # Otherwise, resize depending on the number of VMs
                winheight = vmnum * 100 + 50
                self.setFixedHeight(winheight)
        return winheight

    def get_os_icon(self, os):
        """
            Description: Depending on the VM's OS, this method returns
                         which icon should be used to illustrate it.
            Arguments: oVirt-style string representing the VM's OS
            Returns: The file name under IMGDIR that should be shown.
        """

        if 'ubuntu' in os:
            return 'ubuntu'
        elif 'rhel' in os:
            return 'redhat'
        elif 'centos' in os:
            return 'centos'
        elif 'debian' in os:
            return 'debian'
        elif 'linux' in os:
            return 'linux'
        elif 'win' in os:
            return 'windows'
        return 'unknown'

    def generate_toolbar(self):
        """
            Description: There will be a toolbar in the main widget with some buttons,
                         this method will render them.
            Arguments: None
            Returns: Nothing
        """

        global IMGDIR, conf

        self.toolBar = QToolBar(self)

        refreshAction = QAction(QIcon(IMGDIR + 'refresh.png'), _('refresh'),
                                self)
        refreshAction.setShortcut('Ctrl+R')
        refreshAction.triggered.connect(self.refresh_grid)
        self.toolBar.addAction(refreshAction)

        self.forgetCredsAction = QAction(QIcon(IMGDIR + 'forget.png'),
                                         _('forget_credentials'), self)
        self.forgetCredsAction.setShortcut('Ctrl+F')
        self.forgetCredsAction.triggered.connect(self.forget_creds)
        if not isfile(conf.USERCREDSFILE):
            self.forgetCredsAction.setDisabled(True)
        self.toolBar.addAction(self.forgetCredsAction)

        aboutAction = QAction(QIcon(IMGDIR + 'about.png'), _('about'), self)
        aboutAction.setShortcut('Ctrl+I')
        aboutAction.triggered.connect(self.about)
        self.toolBar.addAction(aboutAction)

        exitAction = QAction(QIcon(IMGDIR + 'exit.png'), _('exit'), self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.triggered.connect(self.quit_button)
        self.toolBar.addAction(exitAction)

        self.grid.addWidget(self.toolBar, 0, 3, Qt.AlignRight)

    def make_button(self, filename, tooltip, alignment=Qt.AlignCenter):
        """
            Description: Creates a QLabel which will contain an image and will
                         simulate a button. No associated text will be shown.
            Arguments: 1. filename: The filename of the icon/image to show 
                       2. tooltip: Some text to show as a tooltip to the image
                       3. alignment: Alignment of the button (center by default)
            Returns: The created QLabel button
        """

        global STANDARDCELLCSS, IMGDIR

        filepath = '%s%s%s' % (IMGDIR, filename, '.png')
        icon = QImage(filepath)
        image = QLabel()
        image.setToolTip('<span style="color:#B9B900">%s</span>' % (tooltip))
        image.setStyleSheet(STANDARDCELLCSS)
        image.setPixmap(QPixmap.fromImage(icon))
        image.setAlignment(alignment)

        return image

    def compare_vms(self, vm1, vm2):
        """
            Description: VM list will be sorted by names. This method is the comparison
                         method for two VMs. We just sort them alphabetically.
            Arguments: Two VMs (oVirt VM objects)
            Returns: -1, 0 or 1 depending on the name-based sorting
        """

        if vm1.name.lower() < vm2.name.lower():
            return -1
        if vm1.name.lower() == vm2.name.lower():
            return 0
        return 1

    def p22p3_compare_vms(self, cmpfunct):
        """ Wrapper for Python 2 -> 3 conversion for the old cmp= method of sorted()"""
        class K:
            def __init__(self, obj, *args):
                self.obj = obj

            def __lt__(self, other):
                return cmpfunct(self.obj, other.obj) < 0

            def __gt__(self, other):
                return cmpfunct(self.obj, other.obj) > 0

            def __eq__(self, other):
                return cmpfunct(self.obj, other.obj) == 0

            def __le__(self, other):
                return cmpfunct(self.obj, other.obj) <= 0

            def __ge__(self, other):
                return cmpfunct(self.obj, other.obj) >= 0

            def __ne__(self, other):
                return cmpfunct(self.obj, other.obj) != 0

        return K

    def current_vm_status(self, vmstatus):
        """
            Description: Single translation between oVirt-like status to human-readable status
            Arguments: oVirt-like status
            Returns: Human-readable status
        """

        if vmstatus == 'up':
            hrstatus = _('up')
        elif vmstatus == 'down':
            hrstatus = _('down')
        elif vmstatus == 'powering_down':
            hrstatus = _('powering_down')
        elif vmstatus == 'wait_for_launch':
            hrstatus = _('wait_for_launch')
        elif vmstatus == 'powering_up':
            hrstatus = _('powering_up')
        elif vmstatus == 'reboot_in_progress':
            hrstatus = _('rebooting')
        else:
            hrstatus = 'unknown'
        return hrstatus

    def toggle_vm_action(self, vmstatus):
        """
            Description: Returns the available action for the current VM's status. If machine is up,
                         available action is turn it off and viceversa.
            Arguments: Current vm status
            Returns: Toggle action for the current status.
        """

        if vmstatus == 'up':
            vmaction = _('shut_down')
        if vmstatus == 'down':
            vmaction = _('power_on')
        return vmaction

    def toggle_action_text(self, vmstatus):
        """
            Description: One of the columns shows the current VM's status. This method returns
                         the toggle tooltip text so the user know what will happen if they click
                         on the status icon.
            Arguments: Current vm status
            Returns: The tooltip's informative text.
        """

        rettxt = '%s <b>%s</b>.' % (_('current_vm_status'),
                                    self.current_vm_status(vmstatus))

        if vmstatus == 'up':
            rettxt += ' %s %s' % (_('click_to_action'), _('shut_down'))
        if vmstatus == 'down':
            rettxt += ' %s %s' % (_('click_to_action'), _('power_on'))

        return rettxt

    def change_status(self, rowid):
        """
            Description: If the user clicks on the column which determines VM's status, we'll allow them
                         to change VM's status. This method shows a confirmation dialog and if accepted,
                         it will be notified to oVirt.
            Arguments: The row id that has been clicked. This relationship is stored using the VmData class.
            Returns: Nothing
        """

        global conf

        self.lastclick = int(time())  # Last click timestamp update

        curvmstatus = self.vmdata[rowid].vmstatus
        if curvmstatus != 'up' and curvmstatus != 'down':
            QMessageBox.warning(None,
                                _('apptitle') + ': ' + _('warning'),
                                _('vm_in_unchangeable_status'))
            return

        reply = QMessageBox.question(
            None,
            _('apptitle') + ': ' + _('confirm'),
            '%s <b>%s</b>. %s: <b>%s</b>.' %
            (_('current_vm_status'), self.current_vm_status(curvmstatus),
             _('confirm_vm_status_change'),
             self.toggle_vm_action(curvmstatus)),
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            try:
                vms_service = conf.OVIRTCONN.vms_service()
                vm = vms_service.list(search='id=%s' %
                                      (self.vmdata[rowid].vmid))[0]
            except Error:
                QMessageBox.critical(None,
                                     _('apptitle') + ': ' + _('error'),
                                     _('unexpected_connection_drop'))
                quit()

            if curvmstatus == 'up':
                try:
                    vm_service = vms_service.vm_service(
                        id=self.vmdata[rowid].vmid)
                    vm_service.shutdown()
                    QMessageBox.information(
                        None,
                        _('apptitle') + ': ' + _('success'),
                        _('shutting_down_vm'))
                except Error:
                    QMessageBox.warning(None,
                                        _('apptitle') + ': ' + _('warning'),
                                        _('vm_in_unchangeable_status'))
            if curvmstatus == 'down':
                try:
                    vm_service = vms_service.vm_service(
                        id=self.vmdata[rowid].vmid)
                    vm_service.start()
                    QMessageBox.information(
                        None,
                        _('apptitle') + ': ' + _('success'),
                        _('powering_up_vm'))
                except Error:
                    QMessageBox.warning(None,
                                        _('apptitle') + ': ' + _('warning'),
                                        _('vm_in_unchangeable_status'))

    def get_viewer_ticket(self, vmid):
        """
            Description: Connecting to the machine involves two steps, the first one is obtaining a 'ticket' string
                         for the connection request. This is done making a request to the oVirt API and then parsing
                         the resulting XML document to get the ticket hash. Also, the request may return more than
                         one ticket: One for SPICE and another for VNC. In this case, we'll return the one that
                         the user defined in the settings file (SPICE as default).
            Arguments: The VM UUID in oVirt-format
            Returns: The ticket hash string
        """

        global conf

        req = urllib.request.Request(
            '%s/%s/%s/%s' %
            (conf.CONFIG['ovirturl'], 'vms', vmid, 'graphicsconsoles'))
        # Python 2 -> 3 conversion: encodestring expects a byte-like string, not str
        base64str = encodestring(
            ('%s:%s' % (conf.USERNAME + '@' + conf.CONFIG['ovirtdomain'],
                        conf.PASSWORD)).encode()).decode().replace('\n', '')
        req.add_header('Authorization', 'Basic ' + base64str)
        req.add_header('filter', 'true')

        unverified_ctxt = SSLContext(PROTOCOL_TLSv1)
        tickethash = urllib.request.urlopen(req,
                                            context=unverified_ctxt).read()
        xmlcontent = ET.fromstring(tickethash)

        ticket = None
        for data in xmlcontent.findall('graphics_console'):
            proto = data.findall('protocol')[0]

            if proto.text.lower() == conf.CONFIG['prefproto'].lower():
                return data.get('id')
            else:
                ticket = data.get('id')

        return ticket

    def store_vv_file(self, vmid, ticket):
        """
            Description: Connecting to the machine involves two steps, the second one is obtaining a 'vv' file with the
                         connection parameters, which we can later pipe to virt-viewer and the connection will be opened.
            Arguments: 1. vmid: The VM UUID in oVirt-format.
                       2. ticket: The ticket obtained in the first step (method get_viewer_ticket)
            Returns: The temporary filename with all the parameters to connect to the machine (piped to virt-viewer)
        """

        global conf

        if not ticket:
            return False

        req = urllib.request.Request(
            '%s/%s/%s/%s/%s' %
            (conf.CONFIG['ovirturl'], 'vms', vmid, 'graphicsconsoles', ticket))
        # Python 2 -> 3 conversion: encodestring expects a byte-like string, not str
        base64str = encodestring(
            ('%s:%s' % (conf.USERNAME + '@' + conf.CONFIG['ovirtdomain'],
                        conf.PASSWORD)).encode()).decode().replace('\n', '')
        req.add_header('Authorization', 'Basic ' + base64str)
        req.add_header('Content-Type', 'application/xml')
        req.add_header('Accept', 'application/x-virt-viewer')
        req.add_header('filter', 'true')

        unverified_ctxt = SSLContext(PROTOCOL_TLSv1)
        try:
            contents = urllib.request.urlopen(req,
                                              context=unverified_ctxt).read()
            if conf.CONFIG['fullscreen'] == '1':
                contents = contents.replace('fullscreen=0', 'fullscreen=1')
            filename = '/tmp/viewer-' + str(randint(10000, 99999))
            f = open(filename, 'wb')
            f.write(contents)
            f.close()

            return filename
        except urllib.request.HTTPError as em:
            QMessageBox.critical(
                None,
                _('apptitle') + ': ' + _('error'),
                _('unexpected_request_error') + '(' + str(em.code) + '): ' +
                em.reason + '. ' + _('check_vm_config_updated'))
            return None

    def viewer_exit(self, vmname):
        self.openviewer_vms.remove(
            vmname)  # Remove the VM from the list of opened viewers
        self.reloadsignal.emit(
        )  # Enforce a reload signal to update the status icon ASAP

    def create_viewer_thread(self, vmname, filename):
        global conf

        def runInThread(vmname, onExit, popenArgs):
            viewer = Popen(popenArgs)
            viewer.wait()
            onExit(vmname)
            return

        thread = threading.Thread(target=runInThread,
                                  args=(vmname, self.viewer_exit, [
                                      conf.CONFIG['remote_viewer_path'], '-t',
                                      vmname, '-f', '--',
                                      'file://%s' % (filename)
                                  ]))
        thread.start()

        # Returns immediately after the thread starts
        return thread

    def connect2machine(self, vmid, vmname):
        """
            Description: Connecting to the machine involves two steps, this method does both and
                         makes sure everything is ok to call virt-viewer afterwards.
            Arguments: 1. vmid: The VM UUID in oVirt-format.
                       2. vmname: Just for displaying purposes, the VM name
            Returns: Nothing. Opens the view-viewer display.
        """

        viewer_ticket = self.get_viewer_ticket(vmid)
        filename = self.store_vv_file(vmid, viewer_ticket)

        if filename:
            self.create_viewer_thread(vmname, filename)
        else:
            if vmname in self.openviewer_vms:
                self.openviewer_vms.remove(
                    vmname)  # Remove the VM from the list of opened viewers

            QMessageBox.critical(None,
                                 _('apptitle') + ': ' + _('error'),
                                 _('no_viewer_file'))

    def connect(self, rowid):
        """
            Description: Whenever the user clicks on the 'connect' row, this method will make
                         sure the VM status is up and only then will call the connect2machine method.
            Arguments: The row id that has been clicked. This relationship is stored using the VmData class.
            Returns: Nothing
        """

        self.lastclick = int(time())  # Last click timestamp update

        vmid = self.vmdata[rowid].vmid
        vmname = self.vmdata[rowid].vmname
        vmstatus = self.vmdata[rowid].vmstatus

        if vmstatus != 'up':
            QMessageBox.warning(None,
                                _('apptitle') + ': ' + _('warning'),
                                _('cannot_connect_if_vm_not_up'))
            return

        if vmname in self.openviewer_vms:
            QMessageBox.critical(None,
                                 _('apptitle') + ': ' + _('error'),
                                 _('cannot_open_more_viewer_sessions'))
            return

        self.openviewer_vms.append(vmname)
        self.refresh_grid(
        )  # Enforce a dashboard reload to make the icon refresh

        self.connect2machine(vmid, vmname)

    def acquire_vm_from_vmpool(self, rowid):
        """
            Description: A machine will be acquired by a user if they click on the icon of a VmPool
            Arguments: The row id that has been clicked. This relationship is stored using the VmData class.
            Returns: Nothing
        """

        self.lastclick = int(time())  # Last click timestamp update

        vmtype = self.vmdata[rowid].vmtype

        if vmtype == 'vmpool':
            try:
                QMessageBox.information(None,
                                        _('apptitle') + ': ' + _('info'),
                                        _('acquiring_vm_from_pool'))
                vmpool_service = conf.OVIRTCONN.vm_pools_service()
                vmp = vmpool_service.pool_service(id=self.vmdata[rowid].vmid)
                vmp.allocate_vm()
                self.refresh_grid()
            except Error as e:
                QMessageBox.critical(None,
                                     _('apptitle') + ': ' + _('error'), str(e))
        else:
            QMessageBox.warning(None,
                                _('apptitle') + ': ' + _('warning'),
                                _('object_is_not_a_vmpool'))

    def refresh_grid(self):
        """
            Description: Invoked when the user clicks on the 'Refresh' button in the toolbar. Reloads the board.
            Arguments: None
            Returns: Nothing
        """

        self.lastclick = int(time())  # Last click timestamp update
        self.load_vms()

    def about(self):
        """
            Description: Invoked when the user clicks on the 'About' button in the toolbar.
            Arguments: None
            Returns: Nothing
        """

        self.lastclick = int(time())  # Last click timestamp update
        About()

    def forget_creds(self):
        """
            Description: Invoked when the user clicks on the 'Forget credentials' button in the toolbar.
            Arguments: None
            Returns: Nothing
        """

        global conf

        self.lastclick = int(time())  # Last click timestamp update

        reply = QMessageBox.question(None,
                                     _('apptitle') + ': ' + _('confirm'),
                                     _('confirm_forget_creds'),
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)

        if reply == QMessageBox.Yes:
            remove(conf.USERCREDSFILE)
            self.forgetCredsAction.setDisabled(True)
            QMessageBox.information(None,
                                    _('apptitle') + ': ' + _('success'),
                                    _('creds_forgotten'))

    def list_vmpools(self, row, delta, step, vmpools):
        """
            Description: Creates one row per VmPool that the user has access to.
            Arguments: 1. The index of the first row to loop over.
                       2. Delta step to sum to the progress bar.
                       3. The current step of the progress bar
                       4. The oVirt list of VmPools.
            Returns: The final step of the progress bar
        """

        # For cleanness reasons, we'll firstly show available VmPools
        for vm in vmpools:
            vmname = vm.name

            # OS icon
            ostype = 'vmpool'
            imageOsicon = self.make_button(ostype,
                                           '<b>' + _('vmpool') + '</b>')

            # Machine name
            gridvmname = QLabel(vmname)
            gridvmname.setStyleSheet(STANDARDCELLCSS)
            gridvmname.setAlignment(Qt.AlignCenter)

            # Acquire VM button
            connect = self.make_button('grab', _('grab_vm_vmpool'))
            connect.mousePressEvent = lambda x, r=row: self.acquire_vm_from_vmpool(
                r)

            # Fill row with known info
            self.grid.addWidget(imageOsicon, row, 0)
            self.grid.addWidget(gridvmname, row, 1)
            self.grid.addWidget(connect, row, 2)

            # Store the correspondence between row number <-> VMPool data
            vmd = VmData()
            vmd.vmid = vm.id
            vmd.vmname = vm.name
            vmd.vmstatus = None
            vmd.vmtype = 'vmpool'
            self.vmdata[row] = vmd

            row += 1

            step += delta
            self.pbar.setValue(step)

        return step

    def list_vms(self, row, delta, step, vms):
        """
            Description: Creates one row per VM that the user has access to.
            Arguments: 1. The index of the first row to loop over.
                       2. Delta step to sum to the progress bar.
                       3. The current step of the progress bar
                       4. The oVirt list of VMs.
            Returns: Nothing
        """
        # Now we'll show up the VMs
        for vm in vms:
            vmname = vm.name
            vmstatus = vm.status.value

            # OS icon
            ostype = self.get_os_icon(vm.os.type.lower())
            imageOsicon = self.make_button(
                ostype, '<b>%s</b> OS' % (ostype.capitalize()))

            # Machine name
            gridvmname = QLabel(vmname)
            gridvmname.setStyleSheet(STANDARDCELLCSS)
            gridvmname.setAlignment(Qt.AlignCenter)

            # Connect button. Depending on whether it has already been hit, a different icon
            # will be shown and the behavior will also be different.
            if vmname not in self.openviewer_vms:
                connect = self.make_button('connect', _('connect'))
                connect.mousePressEvent = lambda x, r=row: self.connect(r)
            else:
                connect = self.make_button('viewer',
                                           _('viewer_already_opened'))

            # Status icon
            curaction = self.current_vm_status(vmstatus)
            imageSticon = self.make_button(vmstatus,
                                           self.toggle_action_text(vmstatus))
            imageSticon.mousePressEvent = lambda x, r=row: self.change_status(r
                                                                              )

            # Fill row with known info
            self.grid.addWidget(imageOsicon, row, 0)
            self.grid.addWidget(gridvmname, row, 1)
            self.grid.addWidget(imageSticon, row, 2)
            self.grid.addWidget(connect, row, 3)

            # Store the correspondence between row number <-> VM data
            vmd = VmData()
            vmd.vmid = vm.id
            vmd.vmname = vm.name
            vmd.vmstatus = vmstatus
            vmd.vmtype = 'vm'
            self.vmdata[row] = vmd

            row += 1

            step += delta
            self.pbar.setValue(step)

    def load_vms(self):
        """
            Description: Main core VM loader method. Will connect to oVirt, get the VM list and render them.
            Arguments: None
            Returns: Nothing
        """

        global conf, MAXHEIGHT, BACKGROUNDCSS, STANDARDCELLCSS

        QObjectCleanupHandler().add(self.layout())
        if not conf.USERNAME:
            quit()

        # Used to store row <-> VM correspondence
        self.vmdata = {}

        step = 0

        self.pbarlayout = QGridLayout(self)
        self.pbar = QProgressBar(self)
        self.grid = QGridLayout()
        self.grid.setHorizontalSpacing(0)

        # Initially, set the layout to the progress bar
        self.pbar.setGeometry(250, 250, 200, 100)
        self.pbar.setValue(0)
        self.pbarlayout.addWidget(self.pbar, 0, 0)
        self.setLayout(self.pbarlayout)

        self.setStyleSheet(BACKGROUNDCSS)

        try:
            # Try getting the VM list from oVirt
            vms_serv = conf.OVIRTCONN.vms_service()
            vmpools_serv = conf.OVIRTCONN.vm_pools_service()
            vms = sorted(vms_serv.list(),
                         key=self.p22p3_compare_vms(self.compare_vms))
            vmpools = sorted(vmpools_serv.list(),
                             key=self.p22p3_compare_vms(self.compare_vms))
        except Error:
            QMessageBox.critical(None,
                                 _('apptitle') + ': ' + _('error'),
                                 _('unexpected_connection_drop'))
            quit()

        # Set the main widget height based on the number of VMs
        winheight = self.vm_based_resize(len(vms) + len(vmpools))
        if len(vms) + len(vmpools) > 0:
            delta = int(100 / (len(vms) + len(vmpools)))
        else:
            delta = int(100)

        if vmpools:
            step = self.list_vmpools(1, delta, step, vmpools)
        if vms:
            self.list_vms(len(vmpools) + 1, delta, step, vms)

        # Once loading has concluded, progress bar is dismissed and the layout set to the QGridLayout
        self.pbar.hide()
        QObjectCleanupHandler().add(self.layout())

        # First row is special: Number of VMs + Toolbar
        total_machines = QLabel(
            _('total_machines') + ': <font color="#AA8738">' + str(len(vms)) +
            '</font>, ' + _('total_vmpools') + ': <font color="#AA8738">' +
            str(len(vmpools)) + '</font>', self)
        self.grid.addWidget(total_machines, 0, 0, 1, 3, Qt.AlignCenter)
        self.generate_toolbar()

        # We wrap the main widget inside another widget with a vertical scrollbar
        wrapper = QWidget()
        wrapper.setLayout(self.grid)
        scroll = QScrollArea()
        scroll.setWidget(wrapper)
        scroll.setWidgetResizable(True)
        scroll.setFixedHeight(winheight)
        layout = QVBoxLayout()
        layout.addWidget(scroll)

        layout.setContentsMargins(0, 0, 0, 20)
        self.setLayout(layout)

    def update_status_icon(self, i, newstatus):
        """
            Description: Invoked when the background thread emits the signal announcing a status
                         change, so the corresponding VM status icon should be updated.
            Arguments: i: Row that has changed their status. The VM can be matched with VmData().
                       newstatus: The new status for the VM.
            Returns: Nothing
        """

        imageSticon = self.make_button(newstatus,
                                       self.toggle_action_text(newstatus))
        imageSticon.mousePressEvent = lambda x, r=i: self.change_status(r)
        self.grid.addWidget(imageSticon, i, 2)

    def logout_warn(self):
        """
            Description: Called if the warn_autologout setting has been set in the config. It
                         will warn user to reset their idle, otherwise an enforced logout will
                         be performed by calling the logout() method.
            Arguments: None
            Returns: Nothing
        """

        self.autologoutwarnwin = QMessageBox(None)
        self.autologoutwarnwin.setIcon(QMessageBox.Warning)

        self.autologoutwarnwin.setText(_('auto_logout_warn'))
        self.autologoutwarnwin.setWindowTitle(_('auto_logout_warn_title'))
        self.autologoutwarnwin.setStandardButtons(QMessageBox.Ok)
        self.autologoutwarnwin.buttonClicked.connect(
            self.autologoutwarn_accepted)
        self.autologoutwarnwin.exec_()

    def logout(self, reconnect=False):
        """
            Description: Invoked when the autologout parameter is set in the config and the
                         idle time is overreached. This should require authentication again.
            Arguments: None
            Returns: Nothing
        """

        if conf.OVIRTCONN:
            try:
                conf.SOCKOBJ.close()
            except Error:
                pass

        self.stopThread = True
        conf.USERNAME = None
        self.autologoutWarn = False

        # Hide the layout so next user doesn't see the previous content
        self.hide()

        try:
            self.autologoutwarnwin.accept()
        except AttributeError:
            # Usually when the notify_autologout setting has not been set
            pass

        # This will be called upon autologout events
        if reconnect:
            creds = Credentials(None)
            creds.finished.connect(self.start_vmpane)
            creds.exec_()

    def autologoutwarn_accepted(self):
        """
            Description: Callback issued when the user accepts the message box warning
                         about an imminent autologout event.
            Arguments: None
            Returns: Nothing
        """
        self.lastclick = int(time())
        self.autologoutWarn = False  # This will make the warning be shown next times as well

    def refresh_statuses(self):
        """
            Description: Background thread that will look for VM status changes and
                         send a signal to the main thread so the corresponding icons
                         are updated. Also, if there's a change in the number of VMs
                         that the user controls, the main Widgets will be reloaded.
                         It'll also check the autologout setting & act accordingly.
            Arguments: None
            Returns: Nothing ("infinite" loop)
        """

        global UPDATESLEEPINTERVAL

        autologout = False
        while 1 and not self.stopThread:
            if conf.OVIRTCONN:
                try:
                    vms_service = conf.OVIRTCONN.vms_service()
                    ovirt_num_machines = len(vms_service.list())
                except Error:
                    sys.exit('[ERROR] ' + _('unexpected_connection_drop'))

                if ovirt_num_machines != len(self.vmdata):
                    # If the number of VMs has changed, we should reload the main widget
                    self.reloadsignal.emit()
                else:
                    for i in self.vmdata:
                        vmid = self.vmdata[i].vmid
                        vmstatus = self.vmdata[i].vmstatus
                        try:
                            ovirtvm = vms_service.list(search='id=%s' %
                                                       (vmid))[0]
                        except Error:
                            sys.exit('[ERROR] ' +
                                     _('unexpected_connection_drop'))

                        if ovirtvm:
                            curstatus = ovirtvm.status.value
                            if vmstatus != curstatus:
                                # If there has been a status change, emit the signal to update icons
                                self.vmdata[i].vmstatus = curstatus
                                self.updatesignal.emit(i, curstatus)

                # If there is any currently open viewer, we'll reset the idle time so we don't close the session
                # while there still is any open session.
                if self.openviewer_vms:
                    self.lastclick = int(time())  # Last click timestamp update

                # If the autologout warning has not been shown yet and it's configured, we do so
                if conf.CONFIG['autologout'] != 0 and conf.CONFIG['notify_autologout'] != 0 and not self.autologoutWarn and \
                   (int(time() - self.lastclick) >= (conf.CONFIG['autologout'] - conf.CONFIG['notify_autologout']) * 60):
                    self.autologoutWarn = True
                    self.warnlogoutsignal.emit()

                # If there's no credentials file and autologout is set, we check for the last
                # click and if surpassed, a logout will be performed.
                if conf.CONFIG['autologout'] != 0 and not isfile(
                        conf.USERCREDSFILE):
                    if (int(time()) - self.lastclick) >= (
                            conf.CONFIG['autologout'] * 60):
                        self.stopThread = True
                        autologout = True

                sleep(UPDATESLEEPINTERVAL)
            else:
                return

        if autologout:
            self.logoutsignal.emit(True)

    def restart_thread(self):
        """
            Description: Simply starts or restarts the background thread
            Arguments: None
            Returns: Nothing
        """

        self.stopThread = False
        self.lastclick = int(time())
        self.thread = threading.Thread(target=self.refresh_statuses, args=())
        self.thread.daemon = True  # Daemonize thread
        self.thread.start()

    def start_vmpane(self):
        """
            Description: This method will be called when the Credentials dialog is closed.
                         This should happen on successful authentication. We should then
                         load the main widget and fill it with the VMs that the user has
                         permissions on. Additionally, a background thread will be started
                         to check VM status changed so the main widget is updated should
                         this happen.
            Arguments: None
            Returns: Nothing
        """

        self.show()

        self.load_vms()
        self.center()

        self.restart_thread()

    def confirm_quit(self):
        """
            Description: Asks for confirmation from the user's side to close the app.
            Arguments: None
            Returns: True if the user wants to close the app, False otherwise.
        """

        global conf

        reply = QMessageBox.question(None,
                                     _('apptitle') + ': ' + _('confirm'),
                                     _('confirm_quit'),
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)

        if reply == QMessageBox.Yes:
            self.logout(reconnect=False)
            return True
        else:
            return False

    def quit_button(self):
        """
            Description: Triggered when the Exit button in the Toolbar is hit. Confirmation will
                         be required.
            Arguments: None
            Returns: Nothing, exits if user confirms.
        """

        self.lastclick = int(time())  # Last click timestamp update

        if self.confirm_quit():
            quit()

    def closeEvent(self, event):
        """
            Description: The red 'x'. If the user hits it, we'll ask for confirmation.
            Arguments: None
            Returns: Nothing, exits if users confirms.
        """

        if self.confirm_quit():
            event.accept()
        else:
            event.ignore()

    def initUI(self):
        """
            Description: Sets the size of the widget, the window title, centers
                         the window, connects signals to methods and opens the
                         Credentials dialog if needed.
            Arguments: None
            Returns: Nothing.
        """

        global conf, MAXWIDTH, MAXHEIGHT, IMGDIR, VERSION

        self.setFixedSize(MAXWIDTH, MAXHEIGHT)
        self.center()

        self.setWindowTitle(_('apptitle') + ' ' + VERSION)
        self.setWindowIcon(QIcon(IMGDIR + 'appicon.png'))
        self.show()

        self.updatesignal.connect(self.update_status_icon)
        self.logoutsignal.connect(self.logout)
        self.warnlogoutsignal.connect(self.logout_warn)
        self.reloadsignal.connect(self.load_vms)

        if not conf.USERNAME:
            creds = Credentials(self)
            creds.finished.connect(self.start_vmpane)
            creds.exec_()

    def center(self):
        """
            Description: Just centers the window
            Arguments: None
            Returns: Nothing
        """

        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
Ejemplo n.º 6
0
class InviteSenderDialog(QDialog):
    done = pyqtSignal(QWidget)
    closed = pyqtSignal(QWidget)

    def __init__(self, gateway, gui, folder_names=None):
        super(InviteSenderDialog, self).__init__()
        self.gateway = gateway
        self.gui = gui
        self.folder_names = folder_names
        self.folder_names_humanized = humanized_list(folder_names, 'folders')
        self.settings = {}
        self.pending_invites = []
        self.use_tor = self.gateway.use_tor

        self.setMinimumSize(500, 300)

        header_icon = QLabel(self)
        if self.folder_names:
            icon = QFileIconProvider().icon(
                QFileInfo(
                    self.gateway.get_magic_folder_directory(
                        self.folder_names[0])))
        else:
            icon = QIcon(os.path.join(gateway.nodedir, 'icon'))
            if not icon.availableSizes():
                icon = QIcon(resource('tahoe-lafs.png'))
        header_icon.setPixmap(icon.pixmap(50, 50))

        header_text = QLabel(self)
        if self.folder_names:
            header_text.setText(self.folder_names_humanized)
        else:
            header_text.setText(self.gateway.name)
        header_text.setFont(Font(18))
        header_text.setAlignment(Qt.AlignCenter)

        header_layout = QGridLayout()
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              1)
        header_layout.addWidget(header_icon, 1, 2)
        header_layout.addWidget(header_text, 1, 3)
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              4)

        self.subtext_label = QLabel(self)
        self.subtext_label.setFont(Font(10))
        self.subtext_label.setStyleSheet("color: grey")
        self.subtext_label.setWordWrap(True)
        self.subtext_label.setAlignment(Qt.AlignCenter)

        self.noise_label = QLabel()
        font = Font(16)
        font.setFamily("Courier")
        font.setStyleHint(QFont.Monospace)
        self.noise_label.setFont(font)
        self.noise_label.setStyleSheet("color: grey")

        self.noise_timer = QTimer()
        self.noise_timer.timeout.connect(
            lambda: self.noise_label.setText(b58encode(os.urandom(16))))
        self.noise_timer.start(75)

        self.code_label = QLabel()
        self.code_label.setFont(Font(18))
        self.code_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.code_label.hide()

        self.box_title = QLabel(self)
        self.box_title.setAlignment(Qt.AlignCenter)
        self.box_title.setFont(Font(16))

        self.box = QGroupBox()
        self.box.setAlignment(Qt.AlignCenter)
        self.box.setStyleSheet('QGroupBox {font-size: 16px}')

        self.copy_button = QToolButton()
        self.copy_button.setIcon(QIcon(resource('copy.png')))
        self.copy_button.setToolTip("Copy to clipboard")
        self.copy_button.setStyleSheet('border: 0px; padding: 0px;')
        self.copy_button.hide()

        box_layout = QGridLayout(self.box)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        box_layout.addWidget(self.noise_label, 1, 2)
        box_layout.addWidget(self.code_label, 1, 3)
        box_layout.addWidget(self.copy_button, 1, 4)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)

        self.close_button = QPushButton("Close and cancel invite")
        self.close_button.setAutoDefault(False)

        self.checkmark = QLabel()
        self.checkmark.setPixmap(Pixmap('green_checkmark.png', 32))
        self.checkmark.setAlignment(Qt.AlignCenter)
        self.checkmark.hide()

        self.tor_label = QLabel()
        self.tor_label.setToolTip(
            "This connection is being routed through the Tor network.")
        self.tor_label.setPixmap(Pixmap('tor-onion.png', 24))
        self.tor_label.hide()

        self.progress_bar = QProgressBar()
        self.progress_bar.setMaximum(2)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.hide()

        layout = QGridLayout(self)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 0, 0)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 4)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)
        layout.addLayout(header_layout, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 2, 1)
        layout.addWidget(self.box_title, 3, 2, 1, 3)
        layout.addWidget(self.checkmark, 3, 3)
        layout.addWidget(self.tor_label, 4, 1, 1, 1,
                         Qt.AlignRight | Qt.AlignVCenter)
        layout.addWidget(self.box, 4, 2, 1, 3)
        layout.addWidget(self.progress_bar, 4, 2, 1, 3)
        layout.addWidget(self.subtext_label, 5, 2, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 6, 1)
        layout.addWidget(self.close_button, 7, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 8, 1)

        self.copy_button.clicked.connect(self.on_copy_button_clicked)
        self.close_button.clicked.connect(self.close)

        self.set_box_title("Generating invite code...")
        self.subtext_label.setText("Creating folder invite(s)...\n\n")

        if self.use_tor:
            self.tor_label.show()
            self.progress_bar.setStyleSheet(
                'QProgressBar::chunk {{ background-color: {}; }}'.format(
                    TOR_PURPLE))

        self.go()  # XXX

    def set_box_title(self, text):
        if sys.platform == 'darwin':
            self.box_title.setText(text)
            self.box_title.show()
        else:
            self.box.setTitle(text)

    def on_copy_button_clicked(self):
        code = self.code_label.text()
        for mode in get_clipboard_modes():
            set_clipboard_text(code, mode)
        self.subtext_label.setText(
            "Copied '{}' to clipboard!\n\n".format(code))

    def on_got_code(self, code):
        self.noise_timer.stop()
        self.noise_label.hide()
        self.set_box_title("Your invite code is:")
        self.code_label.setText(code)
        self.code_label.show()
        self.copy_button.show()
        if self.folder_names:
            if len(self.folder_names) == 1:
                abilities = 'download "{}" and modify its contents'.format(
                    self.folder_names[0])
            else:
                abilities = 'download {} and modify their contents'.format(
                    self.folder_names_humanized)
        else:
            abilities = 'connect to "{}" and upload new folders'.format(
                self.gateway.name)
        self.subtext_label.setText(
            "Entering this code on another device will allow it to {}.\n"
            "This code can only be used once.".format(abilities))

    def on_got_introduction(self):
        if sys.platform == 'darwin':
            self.box_title.hide()
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(1)
        self.subtext_label.setText("Connection established; sending invite...")

    def on_send_completed(self):
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(2)
        self.checkmark.show()
        self.close_button.setText("Finish")
        if self.folder_names:
            target = self.folder_names_humanized
        else:
            target = self.gateway.name
        text = "Your invitation to {} was accepted".format(target)
        self.subtext_label.setText("Invite successful!\n {} at {}".format(
            text,
            datetime.now().strftime('%H:%M')))
        if get_preference('notifications', 'invite') != 'false':
            self.gui.show_message("Invite successful", text)

        if self.folder_names:
            for view in self.gui.main_window.central_widget.views:
                if view.gateway.name == self.gateway.name:
                    for folder in self.folder_names:
                        # Immediately tell the Model that there are at least 2
                        # members for this folder, i.e., that it is now shared
                        view.model().on_members_updated(folder, [None, None])

    def handle_failure(self, failure):
        if failure.type == wormhole.errors.LonelyError:
            return
        logging.error(str(failure))
        show_failure(failure, self)
        self.invite_sender.cancel()
        self.close()

    def on_created_invite(self):
        self.subtext_label.setText("Opening wormhole...\n\n")

    def go(self):
        self.invite_sender = InviteSender(self.use_tor)
        self.invite_sender.created_invite.connect(self.on_created_invite)
        self.invite_sender.got_code.connect(self.on_got_code)
        self.invite_sender.got_introduction.connect(self.on_got_introduction)
        self.invite_sender.send_completed.connect(self.on_send_completed)
        self.invite_sender.send(self.gateway, self.folder_names).addErrback(
            self.handle_failure)

    def closeEvent(self, event):
        if self.code_label.text() and self.progress_bar.value() < 2:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Question)
            msg.setWindowTitle("Cancel invitation?")
            msg.setText(
                'Are you sure you wish to cancel the invitation to "{}"?'.
                format(self.gateway.name))
            msg.setInformativeText(
                'The invite code "{}" will no longer be valid.'.format(
                    self.code_label.text()))
            msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msg.setDefaultButton(QMessageBox.No)
            if msg.exec_() == QMessageBox.Yes:
                self.invite_sender.cancel()
                event.accept()
                self.closed.emit(self)
            else:
                event.ignore()
        else:
            event.accept()
            if self.noise_timer.isActive():
                self.noise_timer.stop()
            self.closed.emit(self)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
Ejemplo n.º 7
0
class MainWindow(QWidget):
    def __init__(self, parent=None, flags=Qt.WindowFlags()):

        super().__init__(parent=parent, flags=flags)
        self.opt = 'video'
        self.initUI()
        self.connects()
        self.set_appear()
        self.show()

    def initUI(self):
        self.btn_send = QPushButton(txt_send, self)
        self.btn_send2 = QPushButton(txt_send2, self)
        self.line = QLineEdit('https://www.youtube.com/watch?v=hS5CfP8n_js')
        self.line.setPlaceholderText(txt_line)
        self.btn_send.setStyleSheet(CSS)
        self.btn_send2.setStyleSheet(CSS)
        self.line.setStyleSheet(CSS)
        self.status_text = QLabel(error_txt)
        self.status_text.setStyleSheet("color: red; font-size: 46px;")
        self.load_progress = QProgressBar(self)
        self.load_progress.setStyleSheet(
            f"width: {win_width}px; height: 40px;")
        self.status_text.hide()
        self.load_progress.hide()
        self.layout_line1 = QHBoxLayout()
        self.layout_line2 = QVBoxLayout()
        self.layout_line2.addWidget(self.status_text, alignment=Qt.AlignCenter)
        self.layout_line2.addWidget(self.load_progress,
                                    alignment=Qt.AlignBottom)
        self.layout_line2.addLayout(self.layout_line1)
        self.layout_line3 = QHBoxLayout()
        self.layout_line2.addLayout(self.layout_line3)
        self.layout_line3.addWidget(self.btn_send, alignment=Qt.AlignTop)
        self.layout_line3.addWidget(self.btn_send2, alignment=Qt.AlignTop)
        self.layout_line1.addWidget(self.line, alignment=Qt.AlignBottom)
        self.setLayout(self.layout_line2)

    def save(self):
        sender = self.sender()
        if sender.text() == txt_send2:
            self.opt = 'video'
        else:
            self.opt = 'audio'
        if len(self.line.text()) > 0:
            try:
                self.status_text.hide()
                self.load_progress.show()
                progress = Download(self.line.text(), self.opt)
                self.save_in_file()
                for i in range(101):
                    self.load_progress.setValue(i)
                    if i > 99:
                        self.load_progress.hide()
                        self.load_progress.setValue(0)
                        self.line.setText('')
                        self.status_text.setStyleSheet(
                            "color: green; font-size: 46px;")
                        self.status_text.setText(success_text)
                        self.status_text.show()
                        break
            except:
                self.load_progress.hide()
                self.status_text.setText(error_404)
                self.status_text.setStyleSheet("color: red; font-size: 46px;")
                self.status_text.show()
        else:
            self.status_text.setText(error_txt)
            self.status_text.setStyleSheet("color: red; font-size: 46px;")
            self.status_text.show()

    def save_in_file(self):
        with open('list/list.txt', 'r+') as file:
            urls = file.read().split(";")
            url_count = len(urls)
            url = f"{url_count} - {self.line.text()};\n"
            file.write(url)

    def connects(self):
        self.btn_send.clicked.connect(self.save)
        self.btn_send2.clicked.connect(self.save)

    def set_appear(self):
        self.setWindowTitle(txt_title)
        self.setFixedSize(win_width, win_height)
        self.move(win_x, win_y)
Ejemplo n.º 8
0
class LabelAssistDialog(QDialog):
    """
    A simple UI for showing bookmarks and navigating to them.

    FIXME: For now, this window is tied to a particular lane.
           If your project has more than one lane, then each one
           will have it's own bookmark window, which is kinda dumb.
    """
    def __init__(self, parent, topLevelOperatorView):
        super(LabelAssistDialog, self).__init__(parent)
        
        # Create thread router to populate table on main thread
        self.threadRouter = ThreadRouter(self)
        
        # Set object classification operator view
        self.topLevelOperatorView = topLevelOperatorView
        
        self.setWindowTitle("Label Assist")
        self.setMinimumWidth(500)
        self.setMinimumHeight(700)

        layout = QGridLayout() 
        layout.setContentsMargins(10, 10, 10, 10)
                       
        # Show variable importance table
        rows = 0
        columns = 4
        self.table = QTableWidget(rows, columns)   
        self.table.setHorizontalHeaderLabels(['Frame', 'Max Area', 'Min Area', 'Labels'])
        self.table.verticalHeader().setVisible(False)     
        
        # Select full row on-click and call capture double click
        self.table.setSelectionBehavior(QTableView.SelectRows);
        self.table.doubleClicked.connect(self._captureDoubleClick)
                
        layout.addWidget(self.table, 1, 0, 3, 2) 

        # Create progress bar
        self.progressBar = QProgressBar()
        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(0)
        self.progressBar.hide()
        layout.addWidget(self.progressBar, 4, 0, 1, 2)

        # Create button to populate table
        self.computeButton = QPushButton('Compute object info')
        self.computeButton.clicked.connect(self._triggerTableUpdate)
        layout.addWidget(self.computeButton, 5, 0)
        
        # Create close button
        closeButton = QPushButton('Close')
        closeButton.clicked.connect(self.close)
        layout.addWidget(closeButton, 5, 1)
        
        # Set dialog layout
        self.setLayout(layout)       


    def _triggerTableUpdate(self):
        # Check that object area is included in selected features
        featureNames = self.topLevelOperatorView.SelectedFeatures.value
        
        if 'Standard Object Features' not in featureNames or 'Count' not in featureNames['Standard Object Features']:
            box = QMessageBox(QMessageBox.Warning,
                  'Warning',
                  'Object area is not a selected feature. Please select this feature on: \"Standard Object Features > Shape > Size in pixels\"',
                  QMessageBox.NoButton,
                  self)
            box.show()
            return 
        
        # Clear table
        self.table.clearContents()
        self.table.setRowCount(0)
        self.table.setSortingEnabled(False)
        self.progressBar.show()
        self.computeButton.setEnabled(False)

        def compute_features_for_frame(tIndex, t, features): 
            # Compute features and labels (called in parallel from request pool)
            roi = [slice(None) for i in range(len(self.topLevelOperatorView.LabelImages.meta.shape))]
            roi[tIndex] = slice(t, t+1)
            roi = tuple(roi)

            frame = self.topLevelOperatorView.SegmentationImages(roi).wait()           
            frame = frame.squeeze().astype(numpy.uint32, copy=False)
            
            # Dirty trick: We don't care what we're passing here for the 'image' parameter,
            # but vigra insists that we pass *something*, so we'll cast the label image as float32.
            features[t] = vigra.analysis.extractRegionFeatures(frame.view(numpy.float32),
                                                               frame,
                                                               ['Count'],
                                                               ignoreLabel=0)
            
        tIndex = self.topLevelOperatorView.SegmentationImages.meta.axistags.index('t')
        tMax = self.topLevelOperatorView.SegmentationImages.meta.shape[tIndex]     
        
        features = {}
        labels = {}

        def compute_all_features():
            # Compute features in parallel
            pool = RequestPool()
            for t in range(tMax):
                pool.add( Request( partial(compute_features_for_frame, tIndex, t, features) ) )
            pool.wait()
            
        # Compute labels
        labels = self.topLevelOperatorView.LabelInputs([]).wait()
            
        req = Request(compute_all_features)
        req.notify_finished( partial(self._populateTable, features, labels) )
        req.submit()

    @threadRouted
    def _populateTable(self, features, labels, *args):
        self.progressBar.hide()
        self.computeButton.setEnabled(True)
                
        for time, feature in features.items():
            # Insert row
            rowNum = self.table.rowCount()
            self.table.insertRow(self.table.rowCount())
            
            # Get max and min object areas
            areas = feature['Count']#objectFeatures['Standard Object Features']['Count']
            maxObjArea = numpy.max(areas[numpy.nonzero(areas)])
            minObjArea = numpy.min(areas[numpy.nonzero(areas)])
            
            # Get number of labeled objects
            labelNum = numpy.count_nonzero(labels[time])
            
            # Load fram number
            item = QTableWidgetItem(str(time))
            item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.table.setItem(rowNum, 0, item) 

            # Load max object areas
            item = QTableWidgetItemWithFloatSorting(str("{: .02f}".format(maxObjArea)))
            item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.table.setItem(rowNum, 1, item)
                
            # Load min object areas
            item = QTableWidgetItemWithFloatSorting(str("{: .02f}".format(minObjArea)))
            item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.table.setItem(rowNum, 2, item)
            
            # Load label numbers
            item = QTableWidgetItemWithFloatSorting(str("{: .01f}".format(labelNum)))
            item.setFlags( Qt.ItemIsSelectable |  Qt.ItemIsEnabled )
            self.table.setItem(rowNum, 3, item)
        
        # Resize column size to fit dialog size
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)   
        
        # Sort by max object area
        self.table.setSortingEnabled(True)                         
        self.table.sortByColumn(1, Qt.DescendingOrder)
        

    def _captureDoubleClick(self):
        # Navigate to selected frame
        index = self.table.selectedIndexes()[0]
        frameStr = self.table.model().data(index).toString()
        
        if frameStr:
            frameNum = int(frameStr)
            self.parent().editor.posModel.time = frameNum
Ejemplo n.º 9
0
class MainWindow(QMainWindow):

    """Main window class."""

    def __init__(self):
        """Init class."""
        super(MainWindow, self).__init__()
        self.pixmap_syncthingui = QPixmap(":/images/syncthingui.svg")
        tf = QTransform()
        self.pixmap_syncthingui0 = QPixmap(":/images/syncthingui.svg")
        tf.rotate(90.0)
        self.pixmap_syncthingui1 = self.pixmap_syncthingui0.transformed(tf)
        tf.rotate(180.0)
        self.pixmap_syncthingui2 = self.pixmap_syncthingui0.transformed(tf)
        tf.rotate(270.0)
        self.pixmap_syncthingui3 = self.pixmap_syncthingui0.transformed(tf)

        self.init_gui()
        self.init_menu()
        self.init_systray()

        self.run()

    def init_gui(self):
        """init gui setup"""
        self.setWindowIcon(QIcon(self.pixmap_syncthingui))

        self.progressbar = QProgressBar()
        self.statusBar().showMessage(getoutput(SYNCTHING + ' --version'))
        self.statusBar().addPermanentWidget(self.progressbar)
        self.setWindowTitle(__doc__.strip().capitalize())
        self.setMinimumSize(900, 600)
        self.setMaximumSize(1280, 1024)
        self.resize(self.minimumSize())
        self.center()

        # QWebView
        # self.view = QWebView(self)
        self.view = QWebEngineView(self)
        self.view.loadStarted.connect(self.start_loading)
        self.view.loadFinished.connect(self.finish_loading)
        self.view.loadProgress.connect(self.loading)
        self.view.titleChanged.connect(self.set_title)
        self.view.page().linkHovered.connect(
            lambda link_txt: self.statusBar().showMessage(link_txt[:99], 3000))
        QShortcut("Ctrl++", self, activated=lambda:
                  self.view.setZoomFactor(self.view.zoomFactor() + 0.2))
        QShortcut("Ctrl+-", self, activated=lambda:
                  self.view.setZoomFactor(self.view.zoomFactor() - 0.2))
        QShortcut("Ctrl+0", self, activated=lambda: self.view.setZoomFactor(1))
        QShortcut("Ctrl+q", self, activated=lambda: self.close())

        # syncthing console
        self.consolewidget = QWidget(self)
        # TODO: start at specify (w,h)
        self.consolewidget.setMinimumSize(QSize(200, 100))
        # TODO: setStyleSheet
        # self.consolewidget.setStyleSheet("margin:0px; padding: 0px; \
        # border:1px solid rgb(0, 0, 0);")
        # border-radius: 40px;")
        # TODO read syncthing console visible from setting
        # self.consolewidget.setVisible(False)
        # self.consolewidget.showEvent
        # self.consoletextedit = QPlainTextEdit(parent=self.consolewidget)
        self.consoletoolbar = QWidget(self)
        hlayout = QHBoxLayout()
        hlayout
        self.consoletoolbar.setLayout(hlayout)
        self.consoletextedit = QTextEdit(parent=self.consolewidget)
        self.consoletextedit.setWordWrapMode(QTextOption.NoWrap)
        # self.consoletextedit.setStyleSheet(" border:1px solid rgb(0, 0, 0);")
        # self.consoletextedit.setStyleSheet("margin:0px; padding: 0px;")
        layout = QVBoxLayout()
        layout.addWidget(self.consoletoolbar)
        layout.addWidget(self.consoletextedit)

        self.consolewidget.setLayout(layout)

        self.splitter = QSplitter(Qt.Vertical)
        self.splitter.addWidget(self.view)
        self.splitter.addWidget(self.consolewidget)

        # process
        self.process = QProcess()
        self.process.error.connect(self._process_failed)
        # QProcess emits `readyRead` when there is data to be read
        self.process.readyRead.connect(self._process_dataReady)
        self.process.stateChanged.connect(self._process_stateChanged)
        # Just to prevent accidentally running multiple times
    # Disable the button when process starts, and enable it when it finishes
    # self.process.started.connect(lambda: self.runButton.setEnabled(False))
    # self.process.finished.connect(lambda: self.runButton.setEnabled(True))

        # backend options
        self.chrt = QCheckBox("Smooth CPU ", checked=True)
        self.ionice = QCheckBox("Smooth HDD ", checked=True)
        self.chrt.setToolTip("Use Smooth CPUs priority (recommended)")
        self.ionice.setToolTip("Use Smooth HDDs priority (recommended)")
        self.chrt.setStatusTip(self.chrt.toolTip())
        self.ionice.setStatusTip(self.ionice.toolTip())
        # main toolbar
        self.toolbar = self.addToolBar("SyncthinGUI Toolbar")
        # self.toolbar.addAction(QIcon.fromTheme("media-playback-stop"),
        self.toolbar.addAction(QIcon(":/images/stop.svg"),
                               "Stop Sync", lambda: self.syncthing_stop())
        # self.toolbar.addAction(QIcon.fromTheme("media-playback-start"),
        self.toolbar.addAction(QIcon(":/images/start.svg"),
                               "Restart Sync", lambda: self.run())
        self.toolbar.addSeparator()
        self.toolbar.addWidget(self.chrt)
        self.toolbar.addWidget(self.ionice)
        self.toolbar.addSeparator()
        # TODO: test event API
        self.toolbar.addAction(QIcon(":/images/start.svg"),
                               "test ", lambda: self.test())

        # final gui setup
        self.setCentralWidget(self.splitter)

    def test(self):
        """ test some function """
        print("test")

    def init_menu(self):
        """init menu setup"""
        # file menu
        file_menu = self.menuBar().addMenu("File")
        # TODO: setting menu item
        file_menu.addAction("Exit", lambda: self.close())
        # Syncthing menu
        sync_menu = self.menuBar().addMenu("Syncthing")
        sync_menu.addAction("Start Syncronization", lambda: self.run())
        sync_menu.addAction("Stop Syncronization",
                            lambda: self.syncthing_stop())
        # TODO: restart
        # TODO: reflash F5
        sync_menu.addAction("Open in external browser",
                            lambda: open_new_tab(URL))

        # view menu
        view_menu = self.menuBar().addMenu("View")
        # TODO: syncthing console menu
        view_menu.addAction("syncthing console", lambda: self.show_console)
        #
        zoom_menu = view_menu.addMenu("Zoom browser")
        zoom_menu.addAction(
            "Zoom In",
            lambda: self.view.setZoomFactor(self.view.zoomFactor() + .2))
        zoom_menu.addAction(
            "Zoom Out",
            lambda: self.view.setZoomFactor(self.view.zoomFactor() - .2))
        zoom_menu.addAction(
            "Zoom To...",
            lambda: self.view.setZoomFactor(QInputDialog.getInt(
                self, __doc__, "<b>Zoom factor ?:", 1, 1, 9)[0]))
        zoom_menu.addAction("Zoom Reset", lambda: self.view.setZoomFactor(1))
        view_menu.addSeparator()
        act = view_menu.addAction("View Page Source",
                                  lambda: self.view_syncthing_source)
        act.setDisabled(True)

        # window menu
        window_menu = self.menuBar().addMenu("&Window")
        window_menu.addAction("Minimize", lambda: self.showMinimized())
        window_menu.addAction("Maximize", lambda: self.showMaximized())
        window_menu.addAction("Restore", lambda: self.showNormal())
        window_menu.addAction("Center", lambda: self.center())
        window_menu.addAction("Top-Left", lambda: self.move(0, 0))
        window_menu.addAction("To Mouse",
                              lambda: self.move_to_mouse_position())
        window_menu.addAction("Fullscreen", lambda: self.showFullScreen())
        window_menu.addSeparator()
        window_menu.addAction("Increase size", lambda: self.resize(
            self.size().width() * 1.2, self.size().height() * 1.2))
        window_menu.addAction("Decrease size", lambda: self.resize(
            self.size().width() // 1.2, self.size().height() // 1.2))
        window_menu.addAction("Minimum size", lambda:
                              self.resize(self.minimumSize()))
        window_menu.addAction("Maximum size", lambda:
                              self.resize(self.maximumSize()))
        window_menu.addAction("Horizontal Wide", lambda: self.resize(
            self.maximumSize().width(), self.minimumSize().height()))
        window_menu.addAction("Vertical Tall", lambda: self.resize(
            self.minimumSize().width(), self.maximumSize().height()))
        window_menu.addSeparator()
        window_menu.addAction("Disable Resize",
                              lambda: self.setFixedSize(self.size()))
        # help menu
        help_menu = self.menuBar().addMenu("&Help")
        help_menu.addAction("Support Forum", lambda: open_new_tab(HELP_URL_0))
        help_menu.addAction("Lastest Release",
                            lambda: open_new_tab(HELP_URL_1))
        help_menu.addAction("Documentation", lambda: open_new_tab(HELP_URL_2))
        help_menu.addAction("Bugs", lambda: open_new_tab(HELP_URL_3))
        help_menu.addAction("Source Code", lambda: open_new_tab(HELP_URL_4))
        help_menu.addSeparator()
        help_menu.addAction("About Qt 5", lambda: QMessageBox.aboutQt(self))
        help_menu.addAction("About Python 3",
                            lambda: open_new_tab('https://www.python.org'))
        help_menu.addAction("About " + __doc__,
                            lambda: QMessageBox.about(self, __doc__, HELPMSG))
        help_menu.addSeparator()
        help_menu.addAction("Keyboard Shortcuts", lambda:
                            QMessageBox.information(self, __doc__, SHORTCUTS))
        help_menu.addAction("View GitHub Repo", lambda: open_new_tab(__url__))
        if not sys.platform.startswith("win"):
            help_menu.addAction("Show Source Code", lambda: self.view_source())
        help_menu.addSeparator()
        help_menu.addAction("Check Updates", lambda: self.check_for_updates())

    def init_systray(self):
        """init system tray icon"""
        # self.tray = QSystemTrayIcon(QIcon(self.pixmap_syncthingui), self)
        self.tray = AnimatedSysTrayIcon(QIcon(self.pixmap_syncthingui), self)
        self.tray.add_ani_icon(QIcon(self.pixmap_syncthingui0))
        self.tray.add_ani_icon(QIcon(self.pixmap_syncthingui1))
        self.tray.add_ani_icon(QIcon(self.pixmap_syncthingui2))
        self.tray.add_ani_icon(QIcon(self.pixmap_syncthingui3))

        self.tray.setToolTip(__doc__.strip().capitalize())
        traymenu = QMenu(self)
        traymenu.addAction(__doc__).setDisabled(True)
        traymenu.addSeparator()
        # to test animate
        # traymenu.addAction("start", lambda: self.tray.animate_start())
        # traymenu.addAction("stop", lambda: self.tray.animate_stop())
        # traymenu.addSeparator()
        traymenu.addAction("Stop Sync", lambda: self.syncthing_stop())
        traymenu.addAction("Restart Sync", lambda: self.run())
        traymenu.addSeparator()
        traymenu.addAction("Show", lambda: self.show_gui())
        traymenu.addAction("Hide", lambda: self.hide())
        traymenu.addSeparator()
        # traymenu.addAction("Open Web", lambda: open_new_tab(URL))
        # traymenu.addAction("Quit All", lambda: self.close())
        traymenu.addAction("Quit All", lambda: self.app_exit())
        self.tray.setContextMenu(traymenu)
        self.tray.show()

    def show_gui(self):
        """
        Helper method to show UI, this should not be needed, but I discovered.
        """
        self.showNormal()
        # webview require 70Mb to show webpage
        self.view.load(QUrl(URL))

    def syncthing_start(self):
        """syncthing start"""
        self.run()

    def syncthing_stop(self):
        """syncthing stop"""
        print("try to stop syncthing")
        self.process.kill()
        # check there is no other syncthing is running!
        for proc in psutil.process_iter():
            # check whether the process name matches
            # print("procress: %s " % proc.name())
            if proc.name() == SYNCTHING:
                proc.kill()

    def run(self):
        """Run bitch run!."""
        # Stop first!
        self.syncthing_stop()

        command_to_run_syncthing = " ".join((
            "ionice --ignore --class 3" if self.ionice.isChecked() else "",
            "chrt --verbose --idle 0" if self.chrt.isChecked() else "",
            SYNCTHING, "-no-browser"))
        print(command_to_run_syncthing)
        self.process.start(command_to_run_syncthing)
        if not self.process.waitForStarted():
            self._process_failed()

    @pyqtSlot()
    def _process_failed(self):
        """Read and return errors."""
        self.statusBar().showMessage("ERROR:Fail:Syncthing blow up in pieces!")
        print("ERROR:Fail:Syncthing blow up in pieces! Wheres your God now?")
        return str(self.process.readAllStandardError()).strip().lower()

    @pyqtSlot()
    def _process_dataReady(self):
        """get process stdout/strerr when data ready"""
        # TODO: format the msg to remove extra b and \n
        msg = str(self.process.readAll())
        lines = msg.split("'")
        tmp = lines[1]
        tmp = tmp.splitlines(0)
        lines = tmp[0].split("\\n")
        for line in lines:
            if line != "":
                # print("1: %s" % line)
                self.consoletextedit.append(line)
        self.consoletextedit.ensureCursorVisible()
        # autoscroll to last line's first character
        self.consoletextedit.moveCursor(QTextCursor.End)
        self.consoletextedit.moveCursor(QTextCursor.StartOfLine)

    @pyqtSlot(QProcess.ProcessState)
    def _process_stateChanged(self, state):
        """ procress_stateChanged """
        # TODO handle procress_stateChanged
        print("procress_stateChanged: %s" % state)

    def center(self):
        """Center Window on the Current Screen,with Multi-Monitor support."""
        window_geometry = self.frameGeometry()
        mousepointer_position = QApplication.desktop().cursor().pos()
        screen = QApplication.desktop().screenNumber(mousepointer_position)
        centerpoint = QApplication.desktop().screenGeometry(screen).center()
        window_geometry.moveCenter(centerpoint)
        self.move(window_geometry.topLeft())

    def move_to_mouse_position(self):
        """Center the Window on the Current Mouse position."""
        window_geometry = self.frameGeometry()
        window_geometry.moveCenter(QApplication.desktop().cursor().pos())
        self.move(window_geometry.topLeft())

    def show_console(self):
        """Show syncthing console"""
        visible = not self.consolewidget.isVisible
        print("bVisible: %s" % visible)
        self.consolewidget.setVisible(True)
        self.consolewidget.resize(QSize(200, 100))

    def view_source(self):
        """ TODO: Call methods to load and display source code."""
        # call(('xdg-open ' if sys.platform.startswith("linux") else 'open ')
        #      + __file__, shell=True)
        pass

    def view_syncthing_source(self):
        """Call methods to load and display web page source code."""
        print("view_syncthing_source start")
        # access_manager = self.view.page().networkAccessManager()
        # reply = access_manager.get(QNetworkRequest(self.view.url()))
        # reply.finished.connect(self.slot_source_downloaded)

    def slot_source_downloaded(self):
        """Show actual page source code."""
        reply = self.sender()
        # TODO: highlight html source editor/viewer
        self.textedit = QPlainTextEdit()
        self.textedit.setAttribute(Qt.WA_DeleteOnClose)
        self.textedit.setReadOnly(True)
        self.textedit.setPlainText(QTextStream(reply).readAll())
        self.textedit.show()
        reply.deleteLater()

    @pyqtSlot()
    def start_loading(self):
        """show progressbar when downloading data"""
        self.progressbar.show()

    @pyqtSlot(bool)
    def finish_loading(self, finished):
        """Finished loading content."""
        if not finished:
            # TODO: When loading fail, what should we do?
            print("load fail")
            if self.process.state() == QProcess.NotRunning:
                self.run()
                self.view.reload()
            # if self.process.state != QProcess.Running:
            #    print("syncthing is not running: %s" % self.process.state())
            # pass
        print("finish_loading: %s" % finished)
        # TODO: WebEngineView does not have following function?
        # self.view.settings().clearMemoryCaches()
        # self.view.settings().clearIconDatabase()

        # print("finish_loading %s" % datetime.strftime(datetime.now(),
        #                                              '%Y-%m-%d %H:%M:%S'))
        # TODO: following line need 6 sec to finish!!
        # TODO: (" INFO: Loading Web UI increases >250Mb RAM!.")
        # self.view.page().mainFrame().evaluateJavaScript(BASE_JS)
        # print("finish_loading %s" % datetime.strftime(datetime.now(),
        #                                             '%Y-%m-%d %H:%M:%S'))
        self.progressbar.hide()

    @pyqtSlot(int)
    def loading(self, idx):
        """loading content"""
        #print("loading %s" % idx)
        self.progressbar.setValue(idx)

    @pyqtSlot(str)
    def set_title(self, title):
        """set title when webview's title change"""
        # print("title: %s" % title)
        if len(title.strip()) > 0:
            self.setWindowTitle(self.view.title()[:99])

    def check_for_updates(self):
        """Method to check for updates from Git repo versus this version."""
        # print("TODO: https://github.com/coolshou/syncthingui/releases/latest")

        print("__version__: %s" % __version__)
        '''
        this_version = str(open(__file__).read())
        print("this_version: %s" % this_version)
        last_version = str(request.urlopen(__source__).read().decode("utf8"))
        print("last_version: %s" % last_version)

        TODO: previous use file compare, when diff then there is new file!!
        if this_version != last_version:
            m = "Theres new Version available!<br>Download update from the web"
        else:
            m = "No new updates!<br>You have the lastest version of" + __doc__
        return QMessageBox.information(self, __doc__.title(), "<b>" + m)
'''
    def closeEvent(self, event):
        """Ask to Quit."""
        if self.tray.isVisible():
            if self.tray.supportsMessages():
                self.tray.showMessage("Info",
                                      "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.")
            else:
                print(" System tray not supports balloon messages ")
            self.hide()
            event.ignore()

    def app_exit(self):
        """exit app"""
        # TODO: do we need to show UI when doing close?
        # self.show_gui()
        # TODO: show QMessageBox on all virtual desktop
        the_conditional_is_true = QMessageBox.question(
            self, __doc__.title(), 'Quit %s?' % __doc__,
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No) == QMessageBox.Yes
        if the_conditional_is_true:
            self.syncthing_stop()
            self.ani_stop = True
            QApplication.instance().quit
            quit()
Ejemplo n.º 10
0
class MainWindow(QMainWindow, Ui_MainWindow):
    '''
    classdocs
    '''

    def __init__(self, app):
        """
        Init
        :param cutecoin.core.app.Application app: application
        :type: cutecoin.core.app.Application
        """
        # Set up the user interface from Designer.
        super().__init__()
        self.setupUi(self)
        QApplication.setWindowIcon(QIcon(":/icons/cutecoin_logo"))
        self.app = app
        logging.debug(app.thread())
        logging.debug(self.thread())
        self.password_asker = None
        self.initialized = False

        self.busybar = QProgressBar(self.statusbar)
        self.busybar.setMinimum(0)
        self.busybar.setMaximum(0)
        self.busybar.setValue(-1)
        self.statusbar.addWidget(self.busybar)
        self.busybar.hide()
        self.app.version_requested.connect(self.latest_version_requested)
        self.app.get_last_version()

        self.combo_referential = QComboBox(self)
        self.combo_referential.setEnabled(False)
        self.combo_referential.currentIndexChanged.connect(self.referential_changed)

        self.status_label = QLabel("", self)
        self.status_label.setTextFormat(Qt.RichText)

        self.label_time = QLabel("", self)

        self.statusbar.addPermanentWidget(self.status_label, 1)
        self.statusbar.addPermanentWidget(self.label_time)
        self.statusbar.addPermanentWidget(self.combo_referential)
        self.update_time()

        self.loader = Loader(self.app)
        self.loader.loaded.connect(self.loader_finished)
        self.loader.connection_error.connect(self.display_error)

        self.homescreen = HomeScreenWidget(self.app)
        self.centralWidget().layout().addWidget(self.homescreen)
        self.homescreen.button_new.clicked.connect(self.open_add_account_dialog)
        self.homescreen.button_import.clicked.connect(self.import_account)
        self.open_ucoin_info = lambda: QDesktopServices.openUrl(QUrl("http://ucoin.io/theoretical/"))
        self.homescreen.button_info.clicked.connect(self.open_ucoin_info)

        self.import_dialog = None
        self.export_dialog = None

        # TODO: There are too much refresh() calls on startup
        self.refresh()

    def open_add_account_dialog(self):
        dialog = ProcessConfigureAccount(self.app, None)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.action_change_account(self.app.current_account.name)

    @pyqtSlot(str)
    def display_error(self, error):
        QMessageBox.critical(self, ":(",
                             error,
                             QMessageBox.Ok)

    @pyqtSlot(str)
    def referential_changed(self, index):
        if self.app.current_account:
            self.app.current_account.set_display_referential(index)
            if self.currencies_tabwidget.currentWidget():
                self.currencies_tabwidget.currentWidget().referential_changed()

    @pyqtSlot()
    def update_time(self):
        date = QDate.currentDate()
        self.label_time.setText("{0}".format(date.toString("dd/MM/yyyy")))
        next_day = date.addDays(1)
        current_time = QDateTime().currentDateTime().toMSecsSinceEpoch()
        next_time = QDateTime(next_day).toMSecsSinceEpoch()
        timer = QTimer()
        timer.timeout.connect(self.update_time)
        timer.start(next_time - current_time)

    @pyqtSlot()
    def delete_contact(self):
        contact = self.sender().data()
        self.app.current_account.contacts.remove(contact)
        self.refresh_contacts()

    @pyqtSlot()
    def edit_contact(self):
        index = self.sender().data()
        dialog = ConfigureContactDialog(self.app.current_account, self, None, index)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()

    def action_change_account(self, account_name):
        def loading_progressed(value, maximum):
            logging.debug("Busybar : {:} : {:}".format(value, maximum))
            self.busybar.setValue(value)
            self.busybar.setMaximum(maximum)
            QApplication.processEvents()

        if self.app.current_account:
            self.app.save_cache(self.app.current_account)

        self.app.current_account = None
        self.refresh()
        QApplication.setOverrideCursor(Qt.BusyCursor)
        self.app.loading_progressed.connect(loading_progressed)
        self.busybar.setMinimum(0)
        self.busybar.setMaximum(0)
        self.busybar.setValue(-1)
        self.busybar.show()
        self.status_label.setText(self.tr("Loading account {0}").format(account_name))
        self.loader.set_account_name(account_name)
        QTimer.singleShot(10, self.loader.load)
        self.homescreen.button_new.hide()
        self.homescreen.button_import.hide()

    @pyqtSlot()
    def loader_finished(self):
        logging.debug("Finished loading")
        self.refresh()
        self.busybar.hide()
        QApplication.setOverrideCursor(Qt.ArrowCursor)
        try:
            self.app.disconnect()
        except:
            logging.debug("Disconnect of app failed")

        self.app.monitor.start_network_watchers()
        QApplication.processEvents()

    def open_transfer_money_dialog(self):
        dialog = TransferMoneyDialog(self.app.current_account,
                                     self.password_asker)
        dialog.accepted.connect(self.refresh_wallets)
        if dialog.exec_() == QDialog.Accepted:
            currency_tab = self.currencies_tabwidget.currentWidget()
            currency_tab.tab_history.table_history.model().sourceModel().refresh_transfers()

    def open_certification_dialog(self):
        dialog = CertificationDialog(self.app.current_account,
                                     self.password_asker)
        dialog.exec_()

    def open_add_contact_dialog(self):
        dialog = ConfigureContactDialog(self.app.current_account, self)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()

    def open_configure_account_dialog(self):
        dialog = ProcessConfigureAccount(self.app, self.app.current_account)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            if self.app.current_account:
                self.action_change_account(self.app.current_account.name)
            else:
                self.refresh()

    def open_preferences_dialog(self):
        dialog = PreferencesDialog(self.app)
        result = dialog.exec_()

    def open_about_popup(self):
        """
        Open about popup window
        """
        aboutDialog = QDialog(self)
        aboutUi = Ui_AboutPopup()
        aboutUi.setupUi(aboutDialog)

        latest = self.app.available_version
        version_info = ""
        version_url = ""
        if not latest[0]:
            version_info = self.tr("Latest release : {version}") \
                .format(version=latest[1])
            version_url = latest[2]

            new_version_text = """
                <p><b>{version_info}</b></p>
                <p><a href="{version_url}">{link_text}</a></p>
                """.format(version_info=version_info,
                            version_url=version_url,
                            link_text=self.tr("Download link"))
        else:
            new_version_text = ""

        text = self.tr("""
        <h1>Cutecoin</h1>

        <p>Python/Qt uCoin client</p>

        <p>Version : {:}</p>
        {new_version_text}

        <p>License : MIT</p>

        <p><b>Authors</b></p>

        <p>inso</p>
        <p>vit</p>
        <p>canercandan</p>
        """).format(__version__, new_version_text=new_version_text)

        aboutUi.label.setText(text)
        aboutDialog.show()

    @pyqtSlot()
    def latest_version_requested(self):
        latest = self.app.available_version
        logging.debug("Latest version requested")
        if not latest[0]:
            version_info = self.tr("Please get the latest release {version}") \
                .format(version=latest[1])
            version_url = latest[2]

            toast.display("Cutecoin", """<p>{version_info}</br>
<a href={version_url}>Download link</a></p>""".format(
                version_info=version_info,
                version_url=version_url))

    def refresh_wallets(self):
        currency_tab = self.currencies_tabwidget.currentWidget()
        if currency_tab:
            currency_tab.refresh_wallets()

    def refresh_communities(self):
        logging.debug("CLEAR")
        self.currencies_tabwidget.clear()
        if self.app.current_account:
            for community in self.app.current_account.communities:
                tab_currency = CurrencyTabWidget(self.app, community,
                                                 self.password_asker,
                                                 self.status_label)
                tab_currency.refresh()
                self.currencies_tabwidget.addTab(tab_currency,
                                                 QIcon(":/icons/currency_icon"),
                                                 community.name)

    def refresh_accounts(self):
        self.menu_change_account.clear()
        signal_mapper = QSignalMapper(self)

        for account_name in sorted(self.app.accounts.keys()):
            action = QAction(account_name, self)
            self.menu_change_account.addAction(action)
            signal_mapper.setMapping(action, account_name)
            action.triggered.connect(signal_mapper.map)
            signal_mapper.mapped[str].connect(self.action_change_account)

    def refresh_contacts(self):
        self.menu_contacts_list.clear()
        if self.app.current_account:
            for index, contact in enumerate(self.app.current_account.contacts):
                contact_menu = self.menu_contacts_list.addMenu(contact['name'])
                edit_action = contact_menu.addAction(self.tr("Edit"))
                edit_action.triggered.connect(self.edit_contact)
                edit_action.setData(index)
                delete_action = contact_menu.addAction(self.tr("Delete"))
                delete_action.setData(contact)
                delete_action.triggered.connect(self.delete_contact)

    def refresh(self):
        '''
        Refresh main window
        When the selected account changes, all the widgets
        in the window have to be refreshed
        '''
        logging.debug("Refresh started")
        self.refresh_accounts()

        if self.app.current_account is None:
            self.currencies_tabwidget.hide()
            self.homescreen.show()
            self.setWindowTitle(self.tr("CuteCoin {0}").format(__version__))
            self.menu_account.setEnabled(False)
            self.action_configure_parameters.setEnabled(False)
            self.action_set_as_default.setEnabled(False)
            self.combo_referential.setEnabled(False)
            self.status_label.setText(self.tr(""))
            self.password_asker = None
        else:
            logging.debug("Show currencies loading")
            self.currencies_tabwidget.show()
            logging.debug("Hide homescreen")
            self.homescreen.hide()
            self.password_asker = PasswordAskerDialog(self.app.current_account)

            self.combo_referential.blockSignals(True)
            self.combo_referential.clear()
            for ref in self.app.current_account.referentials:
                self.combo_referential.addItem(QCoreApplication.translate('Account', ref[4]))

            self.combo_referential.setEnabled(True)
            self.combo_referential.blockSignals(False)
            logging.debug(self.app.preferences)
            self.combo_referential.setCurrentIndex(self.app.preferences['ref'])
            self.menu_account.setEnabled(True)
            self.action_configure_parameters.setEnabled(True)
            self.setWindowTitle(self.tr("CuteCoin {0} - Account : {1}").format(__version__,
                                                                               self.app.current_account.name))

        self.refresh_communities()
        self.refresh_wallets()
        self.refresh_contacts()

    def import_account(self):
        self.import_dialog = ImportAccountDialog(self.app, self)
        self.import_dialog.accepted.connect(self.import_account_accepted)
        self.import_dialog.exec_()

    def import_account_accepted(self):
        # open account after import
        self.action_change_account(self.import_dialog.edit_name.text())

    def export_account(self):
        # Testable way of using a QFileDialog
        self.export_dialog = QFileDialog(self)
        self.export_dialog.setObjectName('ExportFileDialog')
        self.export_dialog.setWindowTitle(self.tr("Export an account"))
        self.export_dialog.setNameFilter(self.tr("All account files (*.acc)"))
        self.export_dialog.setLabelText(QFileDialog.Accept, self.tr('Export'))
        self.export_dialog.accepted.connect(self.export_account_accepted)
        self.export_dialog.show()

    def export_account_accepted(self):
        selected_file = self.export_dialog.selectedFiles()
        if selected_file:
            if selected_file[0][-4:] == ".acc":
                path = selected_file[0]
            else:
                path = selected_file[0] + ".acc"
            self.app.export_account(path, self.app.current_account)

    def closeEvent(self, event):
        if self.app.current_account:
            self.app.save_cache(self.app.current_account)
        self.app.save_persons()
        super().closeEvent(event)

    def showEvent(self, event):
        super().showEvent(event)
        if not self.initialized:
            # if default account in preferences...
            if self.app.preferences['account'] != "":
                logging.debug("Loading default account")
                self.action_change_account(self.app.preferences['account'])
            # no default account...
            else:
                # if at least one account exists, set it as default...
                if len(self.app.accounts) > 0:
                    # capture names sorted alphabetically
                    names = list(self.app.accounts.keys())
                    names.sort()
                    # set first name in list as default in preferences
                    self.app.preferences['account'] = names[0]
                    self.app.save_preferences(self.app.preferences)
                    # open it
                    logging.debug("No default account in preferences. Set %s as default account." % names[0])
                    self.action_change_account(self.app.preferences['account'])

            self.initialized = True
Ejemplo n.º 11
0
class Ui_MainWindow(QMainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()
        self.setWindowIcon(QIcon('icon.ico'))
        self.setFixedSize(481, 447)

    def setupUi(self):
        self.centralwidget = QWidget(self)
        self.verticalLayoutWidget = QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QRect(20, 50, 121, 271))
        self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.checkBox = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox)
        self.checkBox_2 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_2)
        self.checkBox_4 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_4)
        self.checkBox_3 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_3)
        self.checkBox_8 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_8)
        self.checkBox_5 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_5)
        self.checkBox_7 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_7)
        self.checkBox_6 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_6)
        self.checkBox_9 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_9)
        self.verticalLayoutWidget_2 = QWidget(self.centralwidget)
        self.verticalLayoutWidget_2.setGeometry(QRect(170, 50, 131, 271))
        self.verticalLayout_2 = QVBoxLayout(self.verticalLayoutWidget_2)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.checkBox_10 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_10)
        self.checkBox_11 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_11)
        self.checkBox_12 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_12)
        self.checkBox_13 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_13)
        self.checkBox_14 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_14)
        self.checkBox_15 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_15)
        self.checkBox_16 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_16)
        self.checkBox_17 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_17)
        self.checkBox_18 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_18)
        self.verticalLayoutWidget_3 = QWidget(self.centralwidget)
        self.verticalLayoutWidget_3.setGeometry(QRect(330, 50, 131, 271))
        self.verticalLayout_3 = QVBoxLayout(self.verticalLayoutWidget_3)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.checkBox_19 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_19)
        self.checkBox_20 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_20)
        self.checkBox_21 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_21)
        self.checkBox_22 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_22)
        self.checkBox_23 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_23)
        self.checkBox_24 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_24)
        self.checkBox_25 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_25)
        self.checkBox_26 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_26)
        self.checkBox_27 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_27)
        self.label_note = QLabel(self.centralwidget)
        self.label_note.setGeometry(QRect(20, 340, 291, 16))
        self.horizontalLayoutWidget = QWidget(self.centralwidget)
        self.horizontalLayoutWidget.setGeometry(QRect(379, 380, 81, 31))
        self.horizontalLayout = QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.button_uninstall = QPushButton(self.horizontalLayoutWidget)
        self.horizontalLayout.addWidget(self.button_uninstall)
        self.label_info = QLabel(self.centralwidget)
        self.label_info.setGeometry(QRect(20, 20, 331, 20))
        self.progressbar = QProgressBar(self.centralwidget)
        self.progressbar.setGeometry(QRect(20, 40, 175, 10))
        self.progressbar.hide()
        self.horizontalLayoutWidget_2 = QWidget(self.centralwidget)
        self.horizontalLayoutWidget_2.setGeometry(QRect(20, 380, 160, 31))
        self.horizontalLayout_2 = QHBoxLayout(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.button_select_all = QPushButton(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.addWidget(self.button_select_all)
        self.button_deselect_all = QPushButton(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.addWidget(self.button_deselect_all)
        self.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 481, 21))
        self.menuHelp = QMenu(self.menubar)
        self.setMenuBar(self.menubar)
        self.actionRefresh = QAction(self)
        self.actionHomepage = QAction(self)
        self.actionAbout = QAction(self)
        self.actionQuit = QAction(self)
        self.menuHelp.addAction(self.actionRefresh)
        self.menuHelp.addAction(self.actionHomepage)
        self.menuHelp.addAction(self.actionAbout)
        self.menuHelp.addSeparator()
        self.menuHelp.addAction(self.actionQuit)
        self.menubar.addAction(self.menuHelp.menuAction())

        self.retranslateUi()
        QMetaObject.connectSlotsByName(self)

    def retranslateUi(self):
        _translate = QCoreApplication.translate

        self.setWindowTitle(_translate("MainWindow", "PyDebloatX"))

        self.menuHelp.setTitle(_translate("MainWindow", "&Help"))
        self.actionRefresh.setText(_translate("MainWindow", "&Refresh"))
        self.actionRefresh.setShortcut(_translate("MainWindow", "Ctrl+R"))
        self.actionHomepage.setText(_translate("MainWindow", "&Github"))
        self.actionHomepage.setShortcut(_translate("MainWindow", "Ctrl+G"))
        self.actionAbout.setText(_translate("MainWindow", "&About"))
        self.actionAbout.setShortcut(_translate("MainWindow", "Ctrl+A"))
        self.actionQuit.setText(_translate("MainWindow", "&Quit"))
        self.actionQuit.setShortcut(_translate("MainWindow", "Ctrl+Q"))

        self.label_info.setText(
            _translate("MainWindow", "Updating list of installed apps..."))

        self.checkBox.setText(_translate("MainWindow", "3D Viewer"))
        self.checkBox_2.setText(_translate("MainWindow", "Alarms and Clock"))
        self.checkBox_3.setText(_translate("MainWindow", "Calculator"))
        self.checkBox_4.setText(_translate("MainWindow", "Calendar and Mail"))
        self.checkBox_5.setText(_translate("MainWindow", "Camera"))
        self.checkBox_6.setText(_translate("MainWindow", "Get Help"))
        self.checkBox_7.setText(_translate("MainWindow", "Get Started"))
        self.checkBox_8.setText(_translate("MainWindow", "Groove Music"))
        self.checkBox_9.setText(_translate("MainWindow", "Maps"))

        self.checkBox_10.setText(_translate("MainWindow", "Messaging"))
        self.checkBox_11.setText(_translate("MainWindow", "Money"))
        self.checkBox_12.setText(_translate("MainWindow", "Movies && TV"))
        self.checkBox_13.setText(_translate("MainWindow", "News"))
        self.checkBox_14.setText(_translate("MainWindow", "Office"))
        self.checkBox_15.setText(_translate("MainWindow", "OneNote"))
        self.checkBox_16.setText(_translate("MainWindow", "Paint 3D"))
        self.checkBox_17.setText(_translate("MainWindow", "People"))
        self.checkBox_18.setText(_translate("MainWindow", "Photos"))

        self.checkBox_19.setText(_translate("MainWindow", "Skype"))
        self.checkBox_20.setText(_translate("MainWindow", "Solitaire"))
        self.checkBox_21.setText(_translate("MainWindow", "Sports"))
        self.checkBox_22.setText(_translate("MainWindow", "Store"))
        self.checkBox_23.setText(_translate("MainWindow", "Voice Recorder"))
        self.checkBox_24.setText(_translate("MainWindow", "Weather"))
        self.checkBox_25.setText(_translate("MainWindow", "Windows Feedback"))
        self.checkBox_26.setText(_translate("MainWindow", "Xbox"))
        self.checkBox_27.setText(_translate("MainWindow", "Your Phone"))

        self.label_note.setText(
            _translate(
                "MainWindow",
                "NOTE: Microsoft Edge and Cortana can not be uninstalled."))

        self.button_select_all.setText(_translate("MainWindow", "Select All"))
        self.button_deselect_all.setText(
            _translate("MainWindow", "Deselect All"))

        self.button_uninstall.setText(_translate("MainWindow", "Uninstall"))
Ejemplo n.º 12
0
class UpdateCheck(QWidget, PrintError):
    url = "https://electrum-ltc.org/version"
    download_url = "https://electrum-ltc.org/#download"

    VERSION_ANNOUNCEMENT_SIGNING_KEYS = (
        "LWZzbv5SbiRRjBDL6dUYRdBX9Dp89RDZgG",
    )

    def __init__(self, main_window, latest_version=None):
        self.main_window = main_window
        QWidget.__init__(self)
        self.setWindowTitle('Electrum-LTC - ' + _('Update Check'))
        self.content = QVBoxLayout()
        self.content.setContentsMargins(*[10]*4)

        self.heading_label = QLabel()
        self.content.addWidget(self.heading_label)

        self.detail_label = QLabel()
        self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.detail_label.setOpenExternalLinks(True)
        self.content.addWidget(self.detail_label)

        self.pb = QProgressBar()
        self.pb.setMaximum(0)
        self.pb.setMinimum(0)
        self.content.addWidget(self.pb)

        versions = QHBoxLayout()
        versions.addWidget(QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION))))
        self.latest_version_label = QLabel(_("Latest version: {}".format(" ")))
        versions.addWidget(self.latest_version_label)
        self.content.addLayout(versions)

        self.update_view(latest_version)

        self.update_check_thread = UpdateCheckThread(self.main_window)
        self.update_check_thread.checked.connect(self.on_version_retrieved)
        self.update_check_thread.failed.connect(self.on_retrieval_failed)
        self.update_check_thread.start()

        close_button = QPushButton(_("Close"))
        close_button.clicked.connect(self.close)
        self.content.addWidget(close_button)
        self.setLayout(self.content)
        self.show()

    def on_version_retrieved(self, version):
        self.update_view(version)

    def on_retrieval_failed(self):
        self.heading_label.setText('<h2>' + _("Update check failed") + '</h2>')
        self.detail_label.setText(_("Sorry, but we were unable to check for updates. Please try again later."))
        self.pb.hide()

    @staticmethod
    def is_newer(latest_version):
        return latest_version > LooseVersion(version.ELECTRUM_VERSION)

    def update_view(self, latest_version=None):
        if latest_version:
            self.pb.hide()
            self.latest_version_label.setText(_("Latest version: {}".format(latest_version)))
            if self.is_newer(latest_version):
                self.heading_label.setText('<h2>' + _("There is a new update available") + '</h2>')
                url = "<a href='{u}'>{u}</a>".format(u=UpdateCheck.download_url)
                self.detail_label.setText(_("You can download the new version from {}.").format(url))
            else:
                self.heading_label.setText('<h2>' + _("Already up to date") + '</h2>')
                self.detail_label.setText(_("You are already on the latest version of Electrum."))
        else:
            self.heading_label.setText('<h2>' + _("Checking for updates...") + '</h2>')
            self.detail_label.setText(_("Please wait while Electrum checks for available updates."))
Ejemplo n.º 13
0
class TabRewards_gui(QWidget):
    def __init__(self, imgDir, *args, **kwargs):
        QWidget.__init__(self)
        self.imgDir = imgDir
        self.initRewardsForm()
        mainVertical = QVBoxLayout()
        mainVertical.addWidget(self.rewardsForm)
        buttonbox = QHBoxLayout()
        buttonbox.addStretch(1)
        buttonbox.addWidget(self.btn_Cancel)
        mainVertical.addLayout(buttonbox)
        self.setLayout(mainVertical)

    def initRewardsForm(self):
        self.rewardsForm = QGroupBox()
        layout = QFormLayout()
        layout.setContentsMargins(10, 10, 10, 10)
        layout.setSpacing(13)
        layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        # --- ROW 1
        line1 = QHBoxLayout()
        line1.addWidget(QLabel("Account HW"))
        self.edt_hwAccount = QSpinBox()
        self.edt_hwAccount.setMaximum(9999)
        self.edt_hwAccount.setFixedWidth(50)
        self.edt_hwAccount.setToolTip(
            "account number of the hardware wallet.\nIf unsure put 0")
        self.edt_hwAccount.setValue(0)
        line1.addWidget(self.edt_hwAccount)
        line1.addWidget(QLabel("spath from"))
        self.edt_spathFrom = QSpinBox()
        self.edt_spathFrom.setMaximum(9999)
        self.edt_spathFrom.setFixedWidth(50)
        self.edt_spathFrom.setToolTip("starting address n.")
        self.edt_spathFrom.setValue(0)
        line1.addWidget(self.edt_spathFrom)
        line1.addWidget(QLabel("spath to"))
        self.edt_spathTo = QSpinBox()
        self.edt_spathTo.setMaximum(9999)
        self.edt_spathTo.setFixedWidth(50)
        self.edt_spathTo.setToolTip("ending address n.")
        self.edt_spathTo.setValue(10)
        line1.addWidget(self.edt_spathTo)
        line1.addWidget(QLabel("internal/external"))
        self.edt_internalExternal = QSpinBox()
        self.edt_internalExternal.setFixedWidth(50)
        self.edt_internalExternal.setToolTip("ending address n.")
        self.edt_internalExternal.setValue(0)
        self.edt_internalExternal.setMaximum(1)
        line1.addWidget(self.edt_internalExternal)
        line1.addStretch(1)
        self.btn_reload = QPushButton("Load/Refresh")
        self.btn_reload.setToolTip("Reload data from ledger device")
        line1.addWidget(self.btn_reload)
        layout.addRow(line1)
        #  --- ROW 2: address and copy btn
        hBox = QHBoxLayout()
        self.addySelect = QComboBox()
        self.addySelect.setToolTip("Select Address")
        hBox.addWidget(self.addySelect)
        self.btn_Copy = QPushButton()
        self.btn_Copy.setMaximumWidth(45)
        self.btn_Copy.setToolTip("Copy address to clipboard")
        hBox.addWidget(self.btn_Copy)
        layout.addRow(hBox)
        #  --- ROW 3: UTXOs
        self.rewardsList = QVBoxLayout()
        self.rewardsList.statusLabel = QLabel(
            '<b style="color:red">Reload Rewards</b>')
        self.rewardsList.statusLabel.setVisible(True)
        self.rewardsList.addWidget(self.rewardsList.statusLabel)
        self.rewardsList.box = QTableWidget()
        self.rewardsList.box.setMinimumHeight(230)
        # self.rewardsList.box.setMaximumHeight(140)
        self.rewardsList.box.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.rewardsList.box.setSelectionMode(QAbstractItemView.MultiSelection)
        self.rewardsList.box.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.rewardsList.box.setShowGrid(True)
        self.rewardsList.box.setColumnCount(4)
        self.rewardsList.box.setRowCount(0)
        self.rewardsList.box.horizontalHeader().setSectionResizeMode(
            2, QHeaderView.Stretch)
        self.rewardsList.box.verticalHeader().hide()
        item = QTableWidgetItem()
        item.setText("PIVs")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(0, item)
        item = QTableWidgetItem()
        item.setText("Confirmations")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(1, item)
        item = QTableWidgetItem()
        item.setText("TX Hash")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(2, item)
        item = QTableWidgetItem()
        item.setText("TX Output N")
        item.setTextAlignment(Qt.AlignCenter)
        self.rewardsList.box.setHorizontalHeaderItem(3, item)
        self.rewardsList.addWidget(self.rewardsList.box)
        layout.addRow(self.rewardsList)
        # --- ROW 3
        hBox2 = QHBoxLayout()
        self.btn_selectAllRewards = QPushButton("Select All")
        self.btn_selectAllRewards.setToolTip("Select all available UTXOs")
        hBox2.addWidget(self.btn_selectAllRewards)
        self.btn_deselectAllRewards = QPushButton("Deselect All")
        self.btn_deselectAllRewards.setToolTip("Deselect current selection")
        hBox2.addWidget(self.btn_deselectAllRewards)
        hBox2.addWidget(QLabel("Selected UTXOs"))
        self.selectedRewardsLine = QLabel()
        self.selectedRewardsLine.setMinimumWidth(200)
        self.selectedRewardsLine.setStyleSheet("color: purple")
        self.selectedRewardsLine.setToolTip("PIVX to move away")
        hBox2.addWidget(self.selectedRewardsLine)
        hBox2.addStretch(1)
        layout.addRow(hBox2)
        # --- ROW 4
        hBox3 = QHBoxLayout()
        self.destinationLine = QLineEdit()
        self.destinationLine.setToolTip("PIVX address to send PIV to")
        hBox3.addWidget(self.destinationLine)
        hBox3.addWidget(QLabel("Fee"))
        self.feeLine = QDoubleSpinBox()
        self.feeLine.setDecimals(8)
        self.feeLine.setPrefix("PIV  ")
        self.feeLine.setToolTip("Insert a small fee amount")
        self.feeLine.setFixedWidth(150)
        self.feeLine.setSingleStep(0.001)
        hBox3.addWidget(self.feeLine)
        self.btn_sendRewards = QPushButton("Send")
        hBox3.addWidget(self.btn_sendRewards)
        layout.addRow(QLabel("Destination Address"), hBox3)
        hBox4 = QHBoxLayout()
        hBox4.addStretch(1)
        self.loadingLine = QLabel(
            "<b style='color:red'>Preparing TX.</b> Completed: ")
        self.loadingLinePercent = QProgressBar()
        self.loadingLinePercent.setMaximumWidth(200)
        self.loadingLinePercent.setMaximumHeight(10)
        self.loadingLinePercent.setRange(0, 100)
        hBox4.addWidget(self.loadingLine)
        hBox4.addWidget(self.loadingLinePercent)
        self.loadingLine.hide()
        self.loadingLinePercent.hide()
        layout.addRow(hBox4)
        # --- Set Layout
        self.rewardsForm.setLayout(layout)
        # --- ROW 5
        self.btn_Cancel = QPushButton("Clear")

    def resetStatusLabel(self, message=None):
        if message is None:
            self.rewardsList.statusLabel.setText(
                '<em><b style="color:purple">Checking explorer...</b></em>')
        else:
            self.rewardsList.statusLabel.setText(message)
        self.rewardsList.statusLabel.setVisible(True)
Ejemplo n.º 14
0
class RechgEvalWidget(QFrameLayout):

    sig_new_gluedf = QSignal(GLUEDataFrameBase)

    def __init__(self, parent):
        super(RechgEvalWidget, self).__init__(parent)
        self.setWindowTitle('Recharge Calibration Setup')
        self.setWindowFlags(Qt.Window)

        self.wxdset = None
        self.wldset = None
        self.figstack = FigureStackManager(parent=self)

        self.progressbar = QProgressBar()
        self.progressbar.setValue(0)
        self.progressbar.hide()
        self.__initUI__()

        # Set the worker and thread mechanics

        self.rechg_worker = RechgEvalWorker()
        self.rechg_worker.sig_glue_finished.connect(self.receive_glue_calcul)
        self.rechg_worker.sig_glue_progress.connect(self.progressbar.setValue)

        self.rechg_thread = QThread()
        self.rechg_worker.moveToThread(self.rechg_thread)
        self.rechg_thread.started.connect(self.rechg_worker.eval_recharge)

    def __initUI__(self):

        class QRowLayout(QWidget):
            def __init__(self, items, parent=None):
                super(QRowLayout, self).__init__(parent)

                layout = QGridLayout()
                for col, item in enumerate(items):
                    layout.addWidget(item, 0, col)
                layout.setContentsMargins(0, 0, 0, 0)
                layout.setColumnStretch(0, 100)
                self.setLayout(layout)

        # ---- Parameters

        # Specific yield (Sy) :

        self.QSy_min = QDoubleSpinBox(0.05, 3)
        self.QSy_min.setRange(0.001, 1)

        self.QSy_max = QDoubleSpinBox(0.2, 3)
        self.QSy_max.setRange(0.001, 1)

        # Maximum readily available water (RASmax) :

        # units=' mm'

        self.QRAS_min = QDoubleSpinBox(5)
        self.QRAS_min.setRange(0, 999)

        self.QRAS_max = QDoubleSpinBox(40)
        self.QRAS_max.setRange(0, 999)

        # Runoff coefficient (Cro) :

        self.CRO_min = QDoubleSpinBox(0.1, 3)
        self.CRO_min.setRange(0, 1)

        self.CRO_max = QDoubleSpinBox(0.3, 3)
        self.CRO_max.setRange(0, 1)

        # Snowmelt parameters :

        # units=' °C'

        self._Tmelt = QDoubleSpinBox(0, 1)
        self._Tmelt.setRange(-25, 25)

        # units=' mm/°C'

        self._CM = QDoubleSpinBox(4, 1, 0.1, )
        self._CM.setRange(0.1, 100)

        # units=' days'

        self._deltaT = QDoubleSpinBox(0, 0, )
        self._deltaT.setRange(0, 999)

        class QLabelCentered(QLabel):
            def __init__(self, text):
                super(QLabelCentered, self).__init__(text)
                self.setAlignment(Qt.AlignCenter)

        # ---- Parameters

        params_group = QFrameLayout()
        params_group.setContentsMargins(10, 5, 10, 0)  # (L, T, R, B)
        params_group.setObjectName("viewport")
        params_group.setStyleSheet("#viewport {background-color:transparent;}")

        row = 0
        params_group.addWidget(QLabel('Sy :'), row, 0)
        params_group.addWidget(self.QSy_min, row, 1)
        params_group.addWidget(QLabelCentered('to'), row, 2)
        params_group.addWidget(self.QSy_max, row, 3)
        row += 1
        params_group.addWidget(QLabel('RAS<sub>max</sub> :'), row, 0)
        params_group.addWidget(self.QRAS_min, row, 1)
        params_group.addWidget(QLabelCentered('to'), row, 2)
        params_group.addWidget(self.QRAS_max, row, 3)
        params_group.addWidget(QLabel('mm'), row, 4)
        row += 1
        params_group.addWidget(QLabel('Cro :'), row, 0)
        params_group.addWidget(self.CRO_min, row, 1)
        params_group.addWidget(QLabelCentered('to'), row, 2)
        params_group.addWidget(self.CRO_max, row, 3)
        row += 1
        params_group.setRowMinimumHeight(row, 10)
        row += 1
        params_group.addWidget(QLabel('Tmelt :'), row, 0)
        params_group.addWidget(self._Tmelt, row, 1)
        params_group.addWidget(QLabel('°C'), row, 2, 1, 3)
        row += 1
        params_group.addWidget(QLabel('CM :'), row, 0)
        params_group.addWidget(self._CM, row, 1)
        params_group.addWidget(QLabel('mm/°C'), row, 2, 1, 3)
        row += 1
        params_group.addWidget(QLabel('deltaT :'), row, 0)
        params_group.addWidget(self._deltaT, row, 1)
        params_group.addWidget(QLabel('days'), row, 2, 1, 3)
        row += 1
        params_group.setRowStretch(row, 100)
        params_group.setColumnStretch(5, 100)

        # ---- Layout ----

        qtitle = QLabel('Parameter Range')
        qtitle.setAlignment(Qt.AlignCenter)

        sa = QScrollArea()
        sa.setWidget(params_group)
        sa.setWidgetResizable(True)
        sa.setFrameStyle(0)
        sa.setStyleSheet("QScrollArea {background-color:transparent;}")
        sa.setSizePolicy(QSizePolicy(QSizePolicy.Ignored,
                                     QSizePolicy.Preferred))

        # ---- Main Layout

        self.addWidget(qtitle, 0, 0)
        self.addWidget(HSep(), 1, 0)
        self.addWidget(sa, 2, 0)
        self.addWidget(HSep(), 3, 0)
        self.setRowMinimumHeight(4, 5)
        self.addWidget(self.setup_toolbar(), 5, 0)

        self.setRowStretch(2, 100)
        self.setVerticalSpacing(5)
        self.setContentsMargins(0, 0, 0, 10)   # (L, T, R, B)

    def setup_toolbar(self):
        """Setup the toolbar of the widget. """
        toolbar = QWidget()

        btn_calib = QPushButton('Compute Recharge')
        btn_calib.clicked.connect(self.btn_calibrate_isClicked)

        self.btn_show_result = QToolButtonSmall(icons.get_icon('search'))
        self.btn_show_result.clicked.connect(self.figstack.show)
        self.btn_show_result.setToolTip("Show GLUE results.")

        self.btn_save_glue = ExportGLUEButton(self.wxdset)

        layout = QGridLayout(toolbar)
        layout.addWidget(btn_calib, 0, 0)
        layout.addWidget(self.btn_show_result, 0, 1)
        layout.addWidget(self.btn_save_glue, 0, 2)
        layout.setContentsMargins(10, 0, 10, 0)  # (L, T, R, B)

        return toolbar

    def set_wldset(self, wldset):
        """Set the namespace for the water level dataset."""
        self.wldset = wldset
        self.setEnabled(self.wldset is not None and self.wxdset is not None)
        gluedf = None if wldset is None else wldset.get_glue_at(-1)
        self._setup_ranges_from_wldset(gluedf)
        self.figstack.set_gluedf(gluedf)
        self.btn_save_glue.set_model(gluedf)

    def set_wxdset(self, wxdset):
        """Set the namespace for the weather dataset."""
        self.wxdset = wxdset
        self.setEnabled(self.wldset is not None and self.wxdset is not None)

    def _setup_ranges_from_wldset(self, gluedf):
        """
        Set the parameter range values from the last values that were used
        to produce the last GLUE results saved into the project.
        """
        if gluedf is not None:
            self.QSy_min.setValue(min(gluedf['ranges']['Sy']))
            self.QSy_max.setValue(max(gluedf['ranges']['Sy']))

            self.CRO_min.setValue(min(gluedf['ranges']['Cro']))
            self.CRO_max.setValue(max(gluedf['ranges']['Cro']))

            self.QRAS_min.setValue(min(gluedf['ranges']['RASmax']))
            self.QRAS_max.setValue(max(gluedf['ranges']['RASmax']))

            self._Tmelt.setValue(gluedf['params']['tmelt'])
            self._CM.setValue(gluedf['params']['CM'])
            self._deltaT.setValue(gluedf['params']['deltat'])

    def get_Range(self, name):
        if name == 'Sy':
            return [self.QSy_min.value(), self.QSy_max.value()]
        elif name == 'RASmax':
            return [self.QRAS_min.value(), self.QRAS_max.value()]
        elif name == 'Cro':
            return [self.CRO_min.value(), self.CRO_max.value()]
        else:
            raise ValueError('Name must be either Sy, Rasmax or Cro.')

    @property
    def Tmelt(self):
        return self._Tmelt.value()

    @property
    def CM(self):
        return self._CM.value()

    @property
    def deltaT(self):
        return self._deltaT.value()

    def btn_calibrate_isClicked(self):
        """
        Handles when the button to compute recharge and its uncertainty is
        clicked.
        """
        self.start_glue_calcul()

    def start_glue_calcul(self):
        """
        Start the method to evaluate ground-water recharge and its
        uncertainty.
        """
        # Set the parameter ranges.

        self.rechg_worker.Sy = self.get_Range('Sy')
        self.rechg_worker.Cro = self.get_Range('Cro')
        self.rechg_worker.RASmax = self.get_Range('RASmax')

        self.rechg_worker.TMELT = self.Tmelt
        self.rechg_worker.CM = self.CM
        self.rechg_worker.deltat = self.deltaT

        # Set the data and check for errors.

        error = self.rechg_worker.load_data(self.wxdset, self.wldset)
        if error is not None:
            QMessageBox.warning(self, 'Warning', error, QMessageBox.Ok)
            return

        # Start the computation of groundwater recharge.

        self.progressbar.show()
        waittime = 0
        while self.rechg_thread.isRunning():
            time.sleep(0.1)
            waittime += 0.1
            if waittime > 15:
                print('Impossible to quit the thread.')
                return
        self.rechg_thread.start()

    def receive_glue_calcul(self, glue_dataframe):
        """
        Handle the plotting of the results once ground-water recharge has
        been evaluated.
        """
        self.rechg_thread.quit()
        self.progressbar.hide()
        if glue_dataframe is None:
            msg = ("Recharge evaluation was not possible because all"
                   " the models produced were deemed non-behavioural."
                   "\n\n"
                   "This usually happens when the range of values for"
                   " Sy, RASmax, and Cro are too restrictive or when the"
                   " Master Recession Curve (MRC) does not represent well the"
                   " behaviour of the observed hydrograph.")
            QMessageBox.warning(self, 'Warning', msg, QMessageBox.Ok)
        else:
            self.wldset.clear_glue()
            self.wldset.save_glue(glue_dataframe)
            self.sig_new_gluedf.emit(glue_dataframe)

            self.btn_save_glue.set_model(glue_dataframe)
            self.figstack.set_gluedf(glue_dataframe)
Ejemplo n.º 15
0
class Splash(QObject, LogMixin, EventMixin):
    """Splash screen class"""

    def __init__(self, parent, msg = ""):
        """
        Constructor of Splash screen

        :param parent: ui parent
        :param msg: initial message text

        """
        super().__init__()
        self._parent = parent
        self.isHidden = True
        self._progress = 0
        self._progressBar = None
        self.msg = msg

        pixmap = QtGui.QPixmap(380, 100)
        pixmap.fill(QtGui.QColor("darkgreen"))

        self._splash = QSplashScreen(pixmap)
        self._splash.setParent(self._parent)

        self.add_progressbar()

    def add_progressbar(self):
        """Add separate progress bar to splash screen"""

        self._progressBar = QProgressBar(self._splash)
        self._progressBar.setGeometry(self._splash.width() / 10, 8 * self._splash.height() / 10,
                               8 * self._splash.width() / 10, self._splash.height() / 10)
        self._progressBar.hide()

    def setProgress(self, val):
        """
        Set progress bar to ``val``

        If splash has no progressbar, it will be added dynamically.
        Remove progressbar with ``val`` as None.

        :param val: absolut percent value
        :return:
        """
        if val is not None:
            self._progressBar.show()
            self._progressBar.setTextVisible(True)
            self.progress = val
            try:
                self._progressBar.setValue(self.progress)
            except:
                pass
        else:
            self._progressBar.setTextVisible(False)
            self._progressBar.hide()
            self._progressBar.reset()

        if self.isHidden is True:
            self.isHidden = False
            self.show_()

    def incProgress(self, val):
        """
        Increase progressbar value by ``val``

        If splash has no progressbar, it will be added dynamically.
        Remove progressbar with ``val`` as None.

        :param val: value to increase by
        :return:
        """

        if val is not None:
            self._progressBar.show()
            self._progressBar.setTextVisible(True)
            self.progress = self.progress + val
            try:
                self._progressBar.setValue(self.progress)
                qApp.processEvents()
            except:
                pass
        else:
            self._progressBar.setTextVisible(False)
            self._progressBar.hide()
            self._progressBar.reset()

        if self.isHidden is True:
            self.isHidden = False
            self.show_()

    def setParent(self, parent):
        """Set splash's parent"""
        self._parent = parent
        self._splash.setParent(parent)

    @pyqtSlot()
    @pyqtSlot(bool)
    def close(self, dummy = True):
        self.logger.debug("Hide splash")
        self.isHidden = True
        self._progressBar.hide()
        self._progressBar.reset()
        self._splash.close()

    @pyqtSlot()
    @pyqtSlot(str)
    def show_(self, msg = ""):

        if msg != "":
            self._splash.showMessage(msg, QtCore.Qt.AlignCenter, QtCore.Qt.white)
        else:
            self.logger.debug("Show splash, parent: " + str(self._parent))
            self._splash.showMessage(self.msg, QtCore.Qt.AlignCenter, QtCore.Qt.white)

        try:
        #if platform.system() == "Linux":
            parentUi = self._parent.centralwidget.geometry()  # need to use centralwidget for linux preferably, don't know why
        except:
        #else:
            parentUi = self._parent.childrenRect()

        mysize = self._splash.geometry()

        hpos = parentUi.x() + ((parentUi.width() - mysize.width()) / 2)
        vpos = parentUi.y() + ((parentUi.height() - mysize.height()) / 2)

        self._splash.move(hpos, vpos)
        self._splash.show()

        qApp.processEvents()

    @property
    def progress(self):
        return self._progress

    @progress.setter
    def progress(self, value):
        # create new exception handling vor properties
        # if (value != "True") and (value != "False"):
        #    raise ValueError("describe exception")
        if value > 100:
            value = 0
        if value < 0:
            value = 0
        self._progress = value
Ejemplo n.º 16
0
class MainWindow(QMainWindow, Ui_MainWindow):
    # Maintain the list of browser windows so that they do not get garbage
    # collected.
    _window_list = []

    def __init__(self):
        super(MainWindow, self).__init__()

        MainWindow._window_list.append(self)

        self.setupUi(self)

        # Qt Designer (at least to v4.2.1) can't handle arbitrary widgets in a
        # QToolBar - even though uic can, and they are in the original .ui
        # file.  Therefore we manually add the problematic widgets.
        self.lblAddress = QLabel("Address", self.tbAddress)
        self.tbAddress.insertWidget(self.actionGo, self.lblAddress)
        self.addressEdit = QLineEdit(self.tbAddress)
        self.tbAddress.insertWidget(self.actionGo, self.addressEdit)

        self.addressEdit.returnPressed.connect(self.actionGo.trigger)
        self.actionBack.triggered.connect(self.WebBrowser.GoBack)
        self.actionForward.triggered.connect(self.WebBrowser.GoForward)
        self.actionStop.triggered.connect(self.WebBrowser.Stop)
        self.actionRefresh.triggered.connect(self.WebBrowser.Refresh)
        self.actionHome.triggered.connect(self.WebBrowser.GoHome)
        self.actionSearch.triggered.connect(self.WebBrowser.GoSearch)

        self.pb = QProgressBar(self.statusBar())
        self.pb.setTextVisible(False)
        self.pb.hide()
        self.statusBar().addPermanentWidget(self.pb)

        self.WebBrowser.dynamicCall('GoHome()')

    def closeEvent(self, e):
        MainWindow._window_list.remove(self)
        e.accept()

    def on_WebBrowser_TitleChange(self, title):
        self.setWindowTitle("Qt WebBrowser - " + title)

    def on_WebBrowser_ProgressChange(self, a, b):
        if a <= 0 or b <= 0:
            self.pb.hide()
            return

        self.pb.show()
        self.pb.setRange(0, b)
        self.pb.setValue(a)

    def on_WebBrowser_CommandStateChange(self, cmd, on):
        if cmd == 1:
            self.actionForward.setEnabled(on)
        elif cmd == 2:
            self.actionBack.setEnabled(on)

    def on_WebBrowser_BeforeNavigate(self):
        self.actionStop.setEnabled(True)

    def on_WebBrowser_NavigateComplete(self, _):
        self.actionStop.setEnabled(False)

    @pyqtSlot()
    def on_actionGo_triggered(self):
        self.WebBrowser.dynamicCall('Navigate(const QString&)',
                self.addressEdit.text())

    @pyqtSlot()
    def on_actionNewWindow_triggered(self):
        window = MainWindow()
        window.show()
        if self.addressEdit.text().isEmpty():
            return;

        window.addressEdit.setText(self.addressEdit.text())
        window.actionStop.setEnabled(True)
        window.on_actionGo_triggered()

    @pyqtSlot()
    def on_actionAbout_triggered(self):
        QMessageBox.about(self, "About WebBrowser",
                "This Example has been created using the ActiveQt integration into Qt Designer.\n"
                "It demonstrates the use of QAxWidget to embed the Internet Explorer ActiveX\n"
                "control into a Qt application.")

    @pyqtSlot()
    def on_actionAboutQt_triggered(self):
        QMessageBox.aboutQt(self, "About Qt")
class LabelAssistDialog(QDialog):
    """
    A simple UI for showing bookmarks and navigating to them.

    FIXME: For now, this window is tied to a particular lane.
           If your project has more than one lane, then each one
           will have it's own bookmark window, which is kinda dumb.
    """
    def __init__(self, parent, topLevelOperatorView):
        super(LabelAssistDialog, self).__init__(parent)

        # Create thread router to populate table on main thread
        self.threadRouter = ThreadRouter(self)

        # Set object classification operator view
        self.topLevelOperatorView = topLevelOperatorView

        self.setWindowTitle("Label Assist")
        self.setMinimumWidth(500)
        self.setMinimumHeight(700)

        layout = QGridLayout()
        layout.setContentsMargins(10, 10, 10, 10)

        # Show variable importance table
        rows = 0
        columns = 4
        self.table = QTableWidget(rows, columns)
        self.table.setHorizontalHeaderLabels(
            ['Frame', 'Max Area', 'Min Area', 'Labels'])
        self.table.verticalHeader().setVisible(False)

        # Select full row on-click and call capture double click
        self.table.setSelectionBehavior(QTableView.SelectRows)
        self.table.doubleClicked.connect(self._captureDoubleClick)

        layout.addWidget(self.table, 1, 0, 3, 2)

        # Create progress bar
        self.progressBar = QProgressBar()
        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(0)
        self.progressBar.hide()
        layout.addWidget(self.progressBar, 4, 0, 1, 2)

        # Create button to populate table
        self.computeButton = QPushButton('Compute object info')
        self.computeButton.clicked.connect(self._triggerTableUpdate)
        layout.addWidget(self.computeButton, 5, 0)

        # Create close button
        closeButton = QPushButton('Close')
        closeButton.clicked.connect(self.close)
        layout.addWidget(closeButton, 5, 1)

        # Set dialog layout
        self.setLayout(layout)

    def _triggerTableUpdate(self):
        # Check that object area is included in selected features
        featureNames = self.topLevelOperatorView.SelectedFeatures.value

        if 'Standard Object Features' not in featureNames or 'Count' not in featureNames[
                'Standard Object Features']:
            box = QMessageBox(
                QMessageBox.Warning, 'Warning',
                'Object area is not a selected feature. Please select this feature on: \"Standard Object Features > Shape > Size in pixels\"',
                QMessageBox.NoButton, self)
            box.show()
            return

        # Clear table
        self.table.clearContents()
        self.table.setRowCount(0)
        self.table.setSortingEnabled(False)
        self.progressBar.show()
        self.computeButton.setEnabled(False)

        def compute_features_for_frame(tIndex, t, features):
            # Compute features and labels (called in parallel from request pool)
            roi = [
                slice(None) for i in range(
                    len(self.topLevelOperatorView.LabelImages.meta.shape))
            ]
            roi[tIndex] = slice(t, t + 1)
            roi = tuple(roi)

            frame = self.topLevelOperatorView.SegmentationImages(roi).wait()
            frame = frame.squeeze().astype(numpy.uint32, copy=False)

            # Dirty trick: We don't care what we're passing here for the 'image' parameter,
            # but vigra insists that we pass *something*, so we'll cast the label image as float32.
            features[t] = vigra.analysis.extractRegionFeatures(
                frame.view(numpy.float32), frame, ['Count'], ignoreLabel=0)

        tIndex = self.topLevelOperatorView.SegmentationImages.meta.axistags.index(
            't')
        tMax = self.topLevelOperatorView.SegmentationImages.meta.shape[tIndex]

        features = {}
        labels = {}

        def compute_all_features():
            # Compute features in parallel
            pool = RequestPool()
            for t in range(tMax):
                pool.add(
                    Request(
                        partial(compute_features_for_frame, tIndex, t,
                                features)))
            pool.wait()

        # Compute labels
        labels = self.topLevelOperatorView.LabelInputs([]).wait()

        req = Request(compute_all_features)
        req.notify_finished(partial(self._populateTable, features, labels))
        req.submit()

    @threadRouted
    def _populateTable(self, features, labels, *args):
        self.progressBar.hide()
        self.computeButton.setEnabled(True)

        for time, feature in features.items():
            # Insert row
            rowNum = self.table.rowCount()
            self.table.insertRow(self.table.rowCount())

            # Get max and min object areas
            areas = feature[
                'Count']  #objectFeatures['Standard Object Features']['Count']
            maxObjArea = numpy.max(areas[numpy.nonzero(areas)])
            minObjArea = numpy.min(areas[numpy.nonzero(areas)])

            # Get number of labeled objects
            labelNum = numpy.count_nonzero(labels[time])

            # Load fram number
            item = QTableWidgetItem(str(time))
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            self.table.setItem(rowNum, 0, item)

            # Load max object areas
            item = QTableWidgetItemWithFloatSorting(
                str("{: .02f}".format(maxObjArea)))
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            self.table.setItem(rowNum, 1, item)

            # Load min object areas
            item = QTableWidgetItemWithFloatSorting(
                str("{: .02f}".format(minObjArea)))
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            self.table.setItem(rowNum, 2, item)

            # Load label numbers
            item = QTableWidgetItemWithFloatSorting(
                str("{: .01f}".format(labelNum)))
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            self.table.setItem(rowNum, 3, item)

        # Resize column size to fit dialog size
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # Sort by max object area
        self.table.setSortingEnabled(True)
        self.table.sortByColumn(1, Qt.DescendingOrder)

    def _captureDoubleClick(self):
        # Navigate to selected frame
        index = self.table.selectedIndexes()[0]
        frameStr = self.table.model().data(index).toString()

        if frameStr:
            frameNum = int(frameStr)
            self.parent().editor.posModel.time = frameNum
Ejemplo n.º 18
0
class GUISetupMain(QWidget):
    def __init__(self, stack, parent=None):
        super(GUISetupMain, self).__init__(parent)

        # Stack specific info, determined from dropdown menu selection
        self.stack = stack
        self.fileLocationManager = FileLocationManager(self.stack)
        self.sqlController = SqlController()
        self.sqlController.get_animal_info(self.stack)
        self.stain = self.sqlController.histology.counterstain
        self.curr_step = self.sqlController.get_current_step_from_progress_ini(self.stack)

        # Init UI
        self.init_ui()

        # Set buttons functionality
        self.b_1_4.clicked.connect(lambda: self.click_button(self.b_1_4))
        self.b_1_6.clicked.connect(lambda: self.click_button(self.b_1_6))
        self.b_exit.clicked.connect(lambda: self.click_button(self.b_exit))

        # Update buttons
        self.update_buttons()

        # Center the GUI
        self.center()

    def init_ui(self):
        self.grid_buttons = QGridLayout()
        self.grid_bottom = QGridLayout()

        # Grid buttons
        self.b_1_4 = QPushButton("Setup Sorted Filenames")
        self.grid_buttons.addWidget(self.b_1_4)
        self.b_1_6 = QPushButton("Run automatic setup scripts")
        self.grid_buttons.addWidget(self.b_1_6)

        # Grid bottom
        self.progress = QProgressBar(self)
        self.progress.hide()
        self.grid_bottom.addWidget(self.progress)

        self.b_exit = QPushButton("Exit")
        self.b_exit.setDefault(True)
        self.grid_bottom.addWidget(self.b_exit)

        # Super grid
        self.super_grid = QGridLayout()
        self.super_grid.addLayout(self.grid_buttons, 1, 0)
        self.super_grid.addLayout(self.grid_bottom, 2, 0)
        self.setLayout(self.super_grid)
        self.setWindowTitle("Align to Active Brainstem Atlas - Setup Page")
        self.resize(1000, 450)

    def update_buttons(self):
        """
        Locates where you are in the pipeline by reading the brains_info/STACK_progress.ini

        Buttons corresponding to previous steps are marked as "completed", buttons corresponding
        to future steps are marked as "unpressable" and are grayed out.
        """

        self.stain = self.sqlController.histology.counterstain

        try:
            self.curr_step = self.sqlController.get_current_step_from_progress_ini(self.stack)
            print('format grid buttons current step is', self.curr_step)

            curr_step_index = ['1-4', '1-5', '1-6'].index(self.curr_step[:3])
            for index, button in enumerate([self.b_1_4, self.b_1_6]):
                if index <= curr_step_index + 1:
                    button.setEnabled(True)
                else:
                    button.setEnabled(False)

        # If there are no stacks/brains that have been started
        except KeyError:
            for button in [self.b_1_4, self.b_1_6]:
                button.setEnabled(False)

    def click_button(self, button):
        """
        If any of the "grid" buttons are pressed, this is the callback function.
        In this case, "grid" buttons have a one-to_one correspondance to the steps in the pipeline.
        The completion of each step means you move onto the next one.
        """
        # Setup/Create sorted filenames
        if button == self.b_1_4:
            try:
                subprocess.call(['python', 'a_GUI_setup_sorted_filenames.py', self.stack])
                self.update_buttons()
            except Exception as e:
                sys.stderr.write(str(e))
        # Run automatic scripts
        elif button == self.b_1_6:
            message = "This operation will take a long time."
            message += " Several minutes per image."
            QMessageBox.about(self, "Popup Message", message)
            preprocess_setup(self.stack, self.stain)

            #subprocess.call(['python', 'utilities/a_script_preprocess_1.py', self.stack, self.stain])
            subprocess.call(['python', 'a_script_preprocess_2.py', self.stack, self.stain])

            self.sqlController.set_step_completed_in_progress_ini(self.stack, '1-6_setup_scripts')

            """
            pipeline_status = get_pipeline_status(self.stack)
            if not 'preprocess_1' in pipeline_status and \
                    not 'preprocess_2' in pipeline_status and not 'setup' in pipeline_status:
                self.sqlController.set_step_completed_in_progress_ini(self.stack, '1-6_setup_scripts')
                sys.exit(app.exec_())

            pipeline_status = get_pipeline_status(self.stack)
            if pipeline_status == 'a_script_preprocess_3':
                self.sqlController.set_step_completed_in_progress_ini(self.stack, '1-6_setup_scripts')
                sys.exit(app.exec_())
            # else:
            #    print '\n\n\n\n'
            #    print 'pipeline_status:'
            ##    print pipeline_status
            #    print '\n\n\n\n'
            #    #set_step_completed_in_progress_ini( self.stack, '1-6_setup_scripts')
            print('finished in button 4')
            """
        elif button == self.b_exit:
            self.closeEvent(None)

        self.update_buttons()

    def center(self):
        """
        This function simply aligns the GUI to the center of your monitor.
        """
        frameGm = self.frameGeometry()
        screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        frameGm.moveCenter(centerPoint)
        self.move(frameGm.topLeft())

    def closeEvent(self, event):
        sys.exit(app.exec_())
Ejemplo n.º 19
0
class UpdateCheck(QDialog, Logger):
    url = "https://api.github.com/repos/qtumproject/qtum-electrum/releases/latest"
    download_url = "https://github.com/qtumproject/qtum-electrum/releases/latest"

    def __init__(self, *, latest_version=None):
        QDialog.__init__(self)
        self.setWindowTitle('Qtum Electrum - ' + _('Update Check'))
        self.content = QVBoxLayout()
        self.content.setContentsMargins(*[10] * 4)

        self.heading_label = QLabel()
        self.content.addWidget(self.heading_label)

        self.detail_label = QLabel()
        self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.detail_label.setOpenExternalLinks(True)
        self.content.addWidget(self.detail_label)

        self.pb = QProgressBar()
        self.pb.setMaximum(0)
        self.pb.setMinimum(0)
        self.content.addWidget(self.pb)

        versions = QHBoxLayout()
        versions.addWidget(
            QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION))))
        self.latest_version_label = QLabel(_("Latest version: {}".format(" ")))
        versions.addWidget(self.latest_version_label)
        self.content.addLayout(versions)

        self.update_view(latest_version)

        self.update_check_thread = UpdateCheckThread()
        self.update_check_thread.checked.connect(self.on_version_retrieved)
        self.update_check_thread.failed.connect(self.on_retrieval_failed)
        self.update_check_thread.start()

        close_button = QPushButton(_("Close"))
        close_button.clicked.connect(self.close)
        self.content.addWidget(close_button)
        self.setLayout(self.content)
        self.show()

    def on_version_retrieved(self, version):
        self.update_view(version)

    def on_retrieval_failed(self, error):
        self.heading_label.setText('<h2>' + _("Update check failed") + '</h2>')
        self.detail_label.setText(
            _("Sorry, but we were unable to check for updates. Please try again later."
              ) + f"\n{error}")
        self.pb.hide()

    @staticmethod
    def is_newer(latest_version):
        return latest_version > StrictVersion(version.ELECTRUM_VERSION)

    def update_view(self, latest_version=None):
        if latest_version:
            self.pb.hide()
            self.latest_version_label.setText(
                _("Latest version: {}".format(latest_version)))
            if self.is_newer(latest_version):
                self.heading_label.setText(
                    '<h2>' + _("There is a new update available") + '</h2>')
                url = "<a href='{u}'>{u}</a>".format(
                    u=UpdateCheck.download_url)
                self.detail_label.setText(
                    _("You can download the new version from {}.").format(url))
            else:
                self.heading_label.setText('<h2>' + _("Already up to date") +
                                           '</h2>')
                self.detail_label.setText(
                    _("You are already on the latest version of Electrum."))
        else:
            self.heading_label.setText('<h2>' + _("Checking for updates...") +
                                       '</h2>')
            self.detail_label.setText(
                _("Please wait while Electrum checks for available updates."))
Ejemplo n.º 20
0
class Main(QMainWindow):
    def __init__(self):
        super(Main, self).__init__()
        self.curPath, curFilename = os.path.split(os.path.abspath(sys.argv[0]))
        self.rootPath = self.curPath.replace("\\", "/")
        # 全局日志对象
        self.logger = Log()
        # 布局窗口切分对象组
        self.layoutFormScale = {'obj': None, 'offset': 0}
        # 监听对象表
        self.listeners = {}
        # 服务端通讯参数
        self.token = r''
        # 检查数据库链接
        try:
            # 本地配置
            self.configs = Config()
            # 远程配置
            Na_Business_Report.select().limit(1).count()
        except Exception as e:
            self.logger.info(e)
            if (QMessageBox.question(None, "系统提示", " 数据库链接异常,请与管理员联系!",
                                     QMessageBox.Yes) == QMessageBox.Yes):
                self.closeMain(True)

        # 语言对象
        self.trans = QTranslator(self)
        self.changeLanguage(self.configs.language.value)

    '''
    用户登录
    '''

    def login(self, relogin=False):
        if not relogin: self.user = User()
        if (not self.user.account):
            try:
                _dlg = DlgLogin(self)
            except Exception as e:
                print(e)
        if self.user.account:
            return True
        else:
            sys.exit(0)
            return False

    '''语言切换'''

    def changeLanguage(self, _lang):
        if (_lang == '简体中文'):
            self.trans.load(self.rootPath + '/en_ZH')
            app.installTranslator(self.trans)
        else:
            app.removeTranslator(self.trans)

        self.configs = Config()
        pass

    '''
    初始设置
    '''

    def initMain(self):
        # 设置主窗体样式
        self.setStyleSheet(utGetStyleContent(self.curPath, 'app_style'))

        # 启动提示
        self.statusBar().showMessage('可以开始了...')

        # 初始化进度条
        self.progressBar = QProgressBar()
        self.progressLabel = QLabel()
        self.progressLabel.setText("进度:")

        self.statusBar().addPermanentWidget(self.progressLabel)
        self.statusBar().addPermanentWidget(self.progressBar)
        self.progressBar.setGeometry(0, 0, 100, 5)
        self.progressBar.setRange(0, 100)  # 设置进度条的范围
        self.progressBar.setValue(0)
        self.progressBar.setFixedHeight(10)
        self.progressBar.setFixedWidth(200)
        self.progressBar.hide()
        self.progressLabel.hide()

        self.setWindowIcon(QtGui.QIcon(':icons/images/winlogo.png'))
        pass

    '''
    初始化自适应调整布局
    '''

    def resizeEvent(self, event):
        innerHeight = event.size().height() - 75

    '''
    按下退出键提示是否退出系统
    '''

    def keyPressEvent(self, e):
        if e.key() == QtCore.Qt.Key_Escape:
            self.closeMain()

    '''
    关闭主窗口提示
    '''

    def closeEvent(self, event):
        if (not self.closeMain()):
            event.ignore()

    '''关闭主程序'''

    def closeMain(self, skipInquiry=False):
        if skipInquiry == False:
            req = QMessageBox.question(None, "系统提示",
                                       "您确认要退出程序吗? \n如果配置未保存,请先保存再退出!",
                                       QMessageBox.Yes | QMessageBox.No)
            if (req == QMessageBox.Yes):
                try:
                    # TODO 需要优化退出时杀死所有 QtWebEngineProcess 进程问题
                    # 查看浏览器进程
                    # self.logger.info(os.popen('tasklist /FI "IMAGENAME eq QtWebEngineProcess.exe"').read())
                    # 杀浏览器进程
                    os.system('TASKKILL /F /IM QtWebEngineProcess.exe')

                    App.mainFrame.webview.close()
                    if (App.mainFrame.twLogs):
                        App.mainFrame.twLogs.webview.close()
                except Exception as e:
                    pass

                sys.exit(0)
            else:
                return False
        else:
            sys.exit(0)

    '''状态信息 ============================'''

    def statusMsg(self, message):
        if message is not None:
            self.statusBar().showMessage(message)

    '''刷新运行日志事件'''

    def actListenersRunLogs(self, title=''):
        if (self.listeners['RunLogsTab'] is not None):
            self.listeners['RunLogsTab']()
        pass
Ejemplo n.º 21
0
class MainWindow(QMainWindow):
    tableContents = []
    tableColumnCount = 8
    tableRowCount = 10
    workerCount = config['worker_num']  # 线程数
    workers = []  # 保存线程对象
    q = Queue()
    wtime = [0, 0]
    bgColor = QColor(180, 200, 230, 40)
    progressVal = 0
    taskVal = 0

    def __init__(self):
        super(MainWindow, self).__init__()
        self.description = self.tr("""<b>Checker</b><br /><br />
            Version: %s<br />
            %s<br /><br />
            Project: <a href=\"%s\">1dot75cm/repo-checker</a><br />
            License: %s<br />
            Author: <a href=\"mailto:%s\">%s</a>""") % (
            __version__, __descript__, __url__, __license__, __email__,
            __author__)
        self.tableHeaders = [
            self.tr("Name"),
            self.tr("URL"),
            self.tr("Branch"),
            self.tr("RPM date [commit]"),
            self.tr("Release date [commit]"),
            self.tr("Latest date [commit]"),
            self.tr("Status"),
            self.tr("Comment")
        ]
        self.setupUi(self)

    def setupUi(self, MainWindow):
        """初始化主窗口"""
        MainWindow.setObjectName("MainWindow")
        MainWindow.setMinimumSize(QSize(910, 450))
        MainWindow.setWindowTitle(self.tr("Checker"))
        MainWindow.setAnimated(True)

        self.centralwidget = QWidget(MainWindow)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.centralwidget.setSizePolicy(sizePolicy)

        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.verticalLayout.setContentsMargins(5, 5, 5, 5)

        self.tableWidget = QTableWidget(self.centralwidget)
        self.setupTable()
        self.verticalLayout.addWidget(self.tableWidget)

        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setContentsMargins(5, 5, 5, 5)

        self.addButton = QPushButton(self.centralwidget)
        self.addButton.setFixedSize(QSize(25, 25))
        self.addButton.setText("+")
        self.horizontalLayout.addWidget(self.addButton)

        self.delButton = QPushButton(self.centralwidget)
        self.delButton.setFixedSize(QSize(25, 25))
        self.delButton.setText("-")
        self.horizontalLayout.addWidget(self.delButton)

        self.upButton = QPushButton(self.centralwidget)
        self.upButton.setFixedSize(QSize(25, 25))
        self.upButton.setText("↑")
        self.upButton.setObjectName("up")
        self.horizontalLayout.addWidget(self.upButton)

        self.downButton = QPushButton(self.centralwidget)
        self.downButton.setFixedSize(QSize(25, 25))
        self.downButton.setText("↓")
        self.horizontalLayout.addWidget(self.downButton)

        spacerItem = QSpacerItem(40, 20, QSizePolicy.MinimumExpanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)

        self.progressBar = QProgressBar(self.centralwidget)
        self.progressBar.hide()
        self.horizontalLayout.addWidget(self.progressBar)

        self.label = QLabel(self.centralwidget)
        self.horizontalLayout.addWidget(self.label)

        spacerItem = QSpacerItem(40, 20, QSizePolicy.Minimum,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)

        self.checkButton = QPushButton(self.centralwidget)
        self.checkButton.setText(self.tr("Check"))
        self.horizontalLayout.addWidget(self.checkButton)

        self.updateButton = QPushButton(self.centralwidget)
        self.updateButton.setText(self.tr("Update item"))
        self.horizontalLayout.addWidget(self.updateButton)

        self.editRuleButton = QPushButton(self.centralwidget)
        self.editRuleButton.setText(self.tr("Edit rule"))
        self.horizontalLayout.addWidget(self.editRuleButton)

        self.verticalLayout.addLayout(self.horizontalLayout)
        MainWindow.setCentralWidget(self.centralwidget)

        # 菜单
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setGeometry(QRect(0, 0, 780, 34))
        MainWindow.setMenuBar(self.menubar)

        self.fileMenu = QMenu(self.menubar)
        self.fileMenu.setTitle(self.tr("File"))
        self.menubar.addAction(self.fileMenu.menuAction())

        self.toolMenu = QMenu(self.menubar)
        self.toolMenu.setTitle(self.tr("Tool"))
        self.menubar.addAction(self.toolMenu.menuAction())

        self.helpMenu = QMenu(self.menubar)
        self.helpMenu.setTitle(self.tr("Help"))
        self.menubar.addAction(self.helpMenu.menuAction())

        self.statusbar = QStatusBar(MainWindow)
        MainWindow.setStatusBar(self.statusbar)

        # 菜单项
        self.aboutAction = QAction(MainWindow)
        self.aboutAction.setText(self.tr("About"))
        self.aboutAction.setObjectName("about")
        self.aboutQtAction = QAction(MainWindow)
        self.aboutQtAction.setText(self.tr("About Qt"))
        self.aboutQtAction.setObjectName("about_qt")
        self.openAction = QAction(MainWindow)
        self.openAction.setText(self.tr("&Open"))
        self.openAction.setShortcut('Ctrl+O')
        self.openAction.setStatusTip(self.tr('Open a file'))
        self.openAction.setObjectName("open")
        self.openUrlAction = QAction(MainWindow)
        self.openUrlAction.setText(self.tr("Open &url"))
        self.openUrlAction.setShortcut('Ctrl+U')
        self.openUrlAction.setStatusTip(self.tr('Open a file with url'))
        self.saveAction = QAction(MainWindow)
        self.saveAction.setText(self.tr("&Save"))
        self.saveAction.setShortcut('Ctrl+S')
        self.saveAction.setStatusTip(self.tr('Save a file'))
        self.saveAction.setObjectName("save")
        self.saveAsAction = QAction(MainWindow)
        self.saveAsAction.setText(self.tr("Save As"))
        self.saveAsAction.setObjectName("save_as")
        self.closeAction = QAction(MainWindow)
        self.closeAction.setText(self.tr("&Close"))
        self.closeAction.setShortcut('Ctrl+W')
        self.closeAction.setStatusTip(self.tr('Close current page'))
        self.exitAction = QAction(MainWindow)
        self.exitAction.setText(self.tr("&Exit"))
        self.exitAction.setShortcut('Ctrl+Q')
        self.exitAction.setStatusTip(self.tr('Exit application'))
        self.settingAction = QAction(MainWindow)
        self.settingAction.setText(self.tr("&Settings"))
        self.settingAction.setShortcut('Ctrl+P')
        self.settingAction.setStatusTip(self.tr('Open settings dialog'))

        self.helpMenu.addAction(self.aboutAction)
        self.helpMenu.addAction(self.aboutQtAction)
        self.toolMenu.addAction(self.settingAction)
        self.fileMenu.addAction(self.openAction)
        self.fileMenu.addAction(self.openUrlAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.saveAction)
        self.fileMenu.addAction(self.saveAsAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.closeAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAction)

        # Signal & Slot
        self.addButton.clicked.connect(self.addRowSlot)
        self.delButton.clicked.connect(self.delRowSlot)
        self.upButton.clicked.connect(self.moveRowSlot)
        self.downButton.clicked.connect(self.moveRowSlot)
        self.checkButton.clicked.connect(self.checkUpdateSlot)
        self.updateButton.clicked.connect(self.updateTableItemSlot)
        self.editRuleButton.clicked.connect(self.editTableItemRuleSlot)
        self.settingAction.triggered.connect(self.showSettingDialogSlot)
        self.aboutAction.triggered.connect(self.showAboutDialogSlot)
        self.aboutQtAction.triggered.connect(self.showAboutDialogSlot)
        self.openAction.triggered.connect(self.showFileDialogSlot)
        self.openUrlAction.triggered.connect(self.showOpenUrlDialogSlot)
        self.saveAction.triggered.connect(self.showFileDialogSlot)
        self.saveAsAction.triggered.connect(self.showFileDialogSlot)
        self.closeAction.triggered.connect(self.tableWidget.clearContents)
        self.exitAction.triggered.connect(self.close)
        self.tableWidget.itemChanged.connect(self.itemChangedSlot)
        self.tableWidget.itemClicked.connect(self.itemClickedForOpenUrlSlot)

    def closeEvent(self, event):
        """关闭应用提示"""
        reply = QMessageBox.question(self, self.tr('Message'),
                                     self.tr("Are you sure to quit?"),
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()  # 接受关闭事件
        else:
            event.ignore()  # 拒绝关闭事件

    def itemClickedForOpenUrlSlot(self, item):
        """Ctrl+left 打开链接"""
        # http://stackoverflow.com/questions/3100090/
        if item.column() == 1 and item.text() and \
                qApp.keyboardModifiers() == Qt.ControlModifier:
            QDesktopServices.openUrl(QUrl(item.text()))  # open url

    def itemChangedSlot(self, item):  # QTableWidgetItem
        """捕获itemChanged信号, 修改表项"""
        try:
            self.tableContents[item.row()].load(item.column(), item.text())
        except IndexError:
            pass

    def moveRowSlot(self):
        """移动行"""
        try:
            sourceRow = self.tableWidget.currentRow()
            destRow = sourceRow - 1 if self.sender().objectName(
            ) == "up" else sourceRow + 1
            if sourceRow != -1:
                sourceItems = self.getRow(sourceRow)
                destItems = self.getRow(destRow)
                self.setRow(destRow, sourceItems)
                self.setRow(sourceRow, destItems)
                self.tableWidget.selectRow(destRow)  # 修改焦点
                log.debug(self.tableContents)
        except AttributeError:
            if self.sender().objectName() == "up":
                QMessageBox.warning(self, self.tr("Warning"),
                                    self.tr("The row is to top."))
            else:
                QMessageBox.warning(self, self.tr("Warning"),
                                    self.tr("The row is to bottom."))

    def getRow(self, rowIndex):
        """获取行"""
        rowItems = []
        for i in range(7):
            item = self.tableWidget.item(rowIndex, i)
            rowItems.append(item.text())
        rowItems.append(self.tableContents[rowIndex].get_rules(ui=True))
        return rowItems

    def setRow(self, rowIndex, rowItems):
        """设置行"""
        for n, i in enumerate(rowItems):
            if n == len(rowItems) - 1:
                self.tableContents[rowIndex].set_rules(i)
            else:
                item = self.tableWidget.item(rowIndex, n)
                item.setText(i)

    def addRowSlot(self):
        """添加行"""
        rowIndex = self.tableWidget.rowCount()
        self.tableWidget.setRowCount(rowIndex + 1)
        self.tableContents.append(Checker())
        self.updateTableSlot(0)  # 更新列表控件
        log.debug(self.tableContents)

    def delRowSlot(self):
        """删除行"""
        # 焦点默认在第一行,要设置setFocusPolicy(Qt.NoFocus)
        rowIndex = self.tableWidget.currentRow()
        if rowIndex != -1:
            self.tableWidget.removeRow(rowIndex)
            self.tableContents.remove(self.tableContents[rowIndex])
            log.debug(self.tableContents)
        else:
            QMessageBox.warning(self, self.tr("Warning"),
                                self.tr("Please select a row."))

    def loadData(self, data):
        """载入数据"""
        self.tableContents = []  # list.clear() Python 3
        for i in data:
            self.tableContents.append(Checker(i))

    def checkUpdateSlot(self):
        """执行更新检查"""
        self.wtime[0] = int(time.time())  # 计时
        self.statusbar.showMessage(self.tr("checking..."))
        self.progressBar.setValue(0)
        self.progressBar.show()
        self.progressVal = 0
        self.taskVal = 0

        for t in range(self.workerCount):
            t = WorkThread(self.q)  # 耗时任务需要用线程执行,再刷新进度条
            t.triggered.connect(self.updateTableSlot)
            self.workers.append(t)
            t.start()  # 执行工作线程

        # 填充队列
        for item in self.tableContents:
            self.q.put(item)

    def updateTableSlot(self, val):
        """线程通过该槽,刷新进度条,表格内容"""
        if val:
            self.taskVal += val
            self.progressVal = self.taskVal / len(self.tableContents) * 100
            self.progressBar.setValue(self.progressVal)
            self.label.setText("%s/%s" %
                               (self.taskVal, len(self.tableContents)))
        self.tableWidget.setRowCount(len(self.tableContents))  # 行数

        for n, i in enumerate(self.tableContents):
            items = i.dump()
            for j in range(self.tableWidget.columnCount()):
                item = QTableWidgetItem(items[j])
                if j in [0, 1]:
                    item.setToolTip(item.text())
                self.tableWidget.setItem(n, j, item)
            self.setStatusColor(n)

        self.setBackgroundColor(self.bgColor)

        if self.progressVal == 100:
            self.wtime[1] = int(time.time())
            self.statusbar.showMessage(
                self.tr("finished (work time %ds)") %
                (self.wtime[1] - self.wtime[0]))

    def updateTableItemSlot(self):
        """更新指定的 RPM 日期为 Release 日期"""
        rowIndex = self.tableWidget.currentRow()
        if rowIndex != -1:
            try:
                item = self.tableWidget.item(rowIndex, 4)
                self.tableWidget.item(rowIndex, 3).setText(item.text())
                self.tableContents[rowIndex].load_meta(item.text())
            except (IndexError, AttributeError):
                QMessageBox.warning(self, self.tr("Warning"),
                                    self.tr("The row is empty."))
        else:
            QMessageBox.warning(self, self.tr("Warning"),
                                self.tr("Please select a row."))

    def editTableItemRuleSlot(self):
        """编辑列表项规则"""
        rowIndex = self.tableWidget.currentRow()
        if rowIndex != -1:
            try:
                # 父控件, 标题, 标签提示, 默认值, window flags
                rules, ok = QInputDialog.getMultiLineText(
                    self, self.tr("Edit rule"),
                    self.
                    tr("XPath rule(format: \"[(time, commit), (time, commit)]\"):"
                       ),
                    re.sub(
                        "\),|],|',", lambda x: "%s\n" % x.group(),
                        str(self.tableContents[rowIndex].get_rules(ui=True))))

                if ok:
                    self.tableContents[rowIndex].set_rules(rules)
            except (IndexError, UnboundLocalError):
                QMessageBox.warning(self, self.tr("Warning"),
                                    self.tr("The row is empty."))
        else:
            QMessageBox.warning(self, self.tr("Warning"),
                                self.tr("Please select a row."))

    def showSettingDialogSlot(self):
        """显示设置对话框"""
        settingDialog = SettingDialog()
        settingDialog.exec_()

    def showAboutDialogSlot(self):
        """显示关于对话框"""
        if self.sender().objectName() == "about":
            QMessageBox.about(self, self.tr("Checker"), self.description)
        else:
            QMessageBox.aboutQt(self, self.tr("Checker"))

    def showOpenUrlDialogSlot(self):
        """通过 Url 打开文件"""
        url, _ = QInputDialog.getText(self, self.tr("Open url"),
                                      self.tr("Enter url:"), QLineEdit.Normal,
                                      "")
        try:
            resp = backend.get(url)
            self.loadData(resp.json())
            self.updateTableSlot(0)  # 更新列表控件
            self.statusbar.showMessage(self.tr("open url successfully"))
        except Exception as e:
            QMessageBox.warning(self, self.tr("Error"),
                                self.tr("Open url failed. See below:\n%s") % e)
            self.statusbar.showMessage(self.tr("open url failed"))

    def loadCsvFile(self, fname):
        """load csv file (old format)"""
        _data = []
        with open(fname, 'r') as fp:
            content = csv.reader(fp)
            for row in content:
                if len(row) and row[0][0] != "#":
                    _data.append(row)
            self.loadData(_data)

    def showFileDialogSlot(self):
        """打开/保存数据至文件"""
        if self.sender().objectName() == "open":
            fname = QFileDialog.getOpenFileName(self, self.tr("Open file"),
                                                os.getcwd())
            fname = fname[0] if isinstance(
                fname, tuple) else fname  # qt5 tuple, qt4 str

            if fname:
                try:
                    with open(fname, 'r') as fp:
                        self.loadData(json.load(fp))
                except AttributeError as e:
                    QMessageBox.warning(
                        self, self.tr("Error"),
                        self.tr("Open file failed. See below:\n%s") % e)
                except:  # json.decoder.JSONDecodeError Python 3
                    try:  # load csv file (old format)
                        self.loadCsvFile(fname)
                    except Exception as e:
                        QMessageBox.warning(
                            self, self.tr("Error"),
                            self.
                            tr("The file does not contain JSON or CSV. See below:\n%s"
                               ) % e)

                self.updateTableSlot(0)  # 更新列表控件
                self.statusbar.showMessage(self.tr("open file successfully"))

        elif self.sender().objectName() in ["save", "save_as"]:
            fname = QFileDialog.getSaveFileName(self, self.tr("Save file"),
                                                os.getcwd())
            fname = fname[0] if isinstance(
                fname, tuple) else fname  # qt5 tuple, qt4 str

            if fname:
                try:
                    with open(fname, 'w') as fp:
                        json.dump(
                            [i.dump(mode="raw") for i in self.tableContents],
                            fp,
                            ensure_ascii=False)
                    self.statusbar.showMessage(self.tr("saved successfully"))
                except AttributeError as e:
                    QMessageBox.warning(
                        self, self.tr("Error"),
                        self.tr("Save file failed. See below:\n%s") % e)

    def setBackgroundColor(self, color):
        """修改背景色"""
        for i in range(self.tableWidget.rowCount()):
            if i % 2 != 0:
                for j in range(self.tableWidget.columnCount()):
                    item = self.tableWidget.item(i, j)
                    if item:
                        item.setBackground(color)

    def setStatusColor(self, rowIndex):
        """修改状态文字颜色"""
        item = self.tableWidget.item(rowIndex, 6)
        if item.text() == "normal":
            item.setForeground(Qt.darkGreen)
        elif item.text() == "update":
            item.setForeground(Qt.darkRed)
        elif item.text() == "error":
            item.setForeground(Qt.darkYellow)
        elif item.text() == "none":
            item.setForeground(Qt.gray)

    def setupTable(self):
        """初始化列表"""
        self.tableWidget.setFocusPolicy(Qt.NoFocus)  # 无焦点
        self.tableWidget.setGridStyle(Qt.DashDotLine)  # 线类型
        self.tableWidget.setWordWrap(True)
        self.tableWidget.setCornerButtonEnabled(True)
        self.tableWidget.horizontalHeader().setVisible(True)  # 显示表头
        #self.tableWidget.horizontalHeader().setSortIndicatorShown(True)  # 排序指示器
        self.tableWidget.horizontalHeader().setStretchLastSection(
            True)  # 扩展最后一列

        self.tableWidget.setColumnCount(self.tableColumnCount)  # 列数
        self.tableWidget.setRowCount(self.tableRowCount)  # 行数

        # 行头
        for i in range(self.tableRowCount):
            item = QTableWidgetItem("%s" % (i + 1))
            self.tableWidget.setVerticalHeaderItem(i, item)  # 行号

        # 列头
        for i in range(self.tableColumnCount):
            item = QTableWidgetItem(self.tableHeaders[i])  # QIcon, str
            self.tableWidget.setHorizontalHeaderItem(i, item)  # 初始化表头

        for i in [3, 4, 5]:
            self.tableWidget.resizeColumnToContents(i)  # 根据内容调整列宽

        # 初始化项目
        for i in range(self.tableRowCount):
            self.tableContents.append(Checker())
            for j in range(self.tableColumnCount):
                item = QTableWidgetItem()
                self.tableWidget.setItem(i, j, item)

        self.setBackgroundColor(self.bgColor)
Ejemplo n.º 22
0
class MainWindow(QMainWindow):
    tableContents = []
    tableColumnCount = 8
    tableRowCount = 10
    workerCount = config['worker_num']  # 线程数
    workers = []  # 保存线程对象
    q = Queue()
    wtime = [0, 0]
    bgColor = QColor(180, 200, 230, 40)
    progressVal = 0
    taskVal = 0

    def __init__(self):
        super(MainWindow, self).__init__()
        self.description = self.tr("""<b>Checker</b><br /><br />
            Version: %s<br />
            %s<br /><br />
            Project: <a href=\"%s\">1dot75cm/repo-checker</a><br />
            License: %s<br />
            Author: <a href=\"mailto:%s\">%s</a>""") % (__version__,
            __descript__, __url__, __license__, __email__, __author__)
        self.tableHeaders = [self.tr("Name"), self.tr("URL"), self.tr("Branch"),
                             self.tr("RPM date [commit]"), self.tr("Release date [commit]"),
                             self.tr("Latest date [commit]"), self.tr("Status"), self.tr("Comment")]
        self.setupUi(self)

    def setupUi(self, MainWindow):
        """初始化主窗口"""
        MainWindow.setObjectName("MainWindow")
        MainWindow.setMinimumSize(QSize(910, 450))
        MainWindow.setWindowTitle(self.tr("Checker"))
        MainWindow.setAnimated(True)

        self.centralwidget = QWidget(MainWindow)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.centralwidget.setSizePolicy(sizePolicy)

        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.verticalLayout.setContentsMargins(5, 5, 5, 5)

        self.tableWidget = QTableWidget(self.centralwidget)
        self.setupTable()
        self.verticalLayout.addWidget(self.tableWidget)

        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setContentsMargins(5, 5, 5, 5)

        self.addButton = QPushButton(self.centralwidget)
        self.addButton.setFixedSize(QSize(25, 25))
        self.addButton.setText("+")
        self.horizontalLayout.addWidget(self.addButton)

        self.delButton = QPushButton(self.centralwidget)
        self.delButton.setFixedSize(QSize(25, 25))
        self.delButton.setText("-")
        self.horizontalLayout.addWidget(self.delButton)

        self.upButton = QPushButton(self.centralwidget)
        self.upButton.setFixedSize(QSize(25, 25))
        self.upButton.setText("↑")
        self.upButton.setObjectName("up")
        self.horizontalLayout.addWidget(self.upButton)

        self.downButton = QPushButton(self.centralwidget)
        self.downButton.setFixedSize(QSize(25, 25))
        self.downButton.setText("↓")
        self.horizontalLayout.addWidget(self.downButton)

        spacerItem = QSpacerItem(40, 20, QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)

        self.progressBar = QProgressBar(self.centralwidget)
        self.progressBar.hide()
        self.horizontalLayout.addWidget(self.progressBar)

        self.label = QLabel(self.centralwidget)
        self.horizontalLayout.addWidget(self.label)

        spacerItem = QSpacerItem(40, 20, QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)

        self.checkButton = QPushButton(self.centralwidget)
        self.checkButton.setText(self.tr("Check"))
        self.horizontalLayout.addWidget(self.checkButton)

        self.updateButton = QPushButton(self.centralwidget)
        self.updateButton.setText(self.tr("Update item"))
        self.horizontalLayout.addWidget(self.updateButton)

        self.editRuleButton = QPushButton(self.centralwidget)
        self.editRuleButton.setText(self.tr("Edit rule"))
        self.horizontalLayout.addWidget(self.editRuleButton)

        self.verticalLayout.addLayout(self.horizontalLayout)
        MainWindow.setCentralWidget(self.centralwidget)

        # 菜单
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setGeometry(QRect(0, 0, 780, 34))
        MainWindow.setMenuBar(self.menubar)

        self.fileMenu = QMenu(self.menubar)
        self.fileMenu.setTitle(self.tr("File"))
        self.menubar.addAction(self.fileMenu.menuAction())

        self.toolMenu = QMenu(self.menubar)
        self.toolMenu.setTitle(self.tr("Tool"))
        self.menubar.addAction(self.toolMenu.menuAction())

        self.helpMenu = QMenu(self.menubar)
        self.helpMenu.setTitle(self.tr("Help"))
        self.menubar.addAction(self.helpMenu.menuAction())

        self.statusbar = QStatusBar(MainWindow)
        MainWindow.setStatusBar(self.statusbar)

        # 菜单项
        self.aboutAction = QAction(MainWindow)
        self.aboutAction.setText(self.tr("About"))
        self.aboutAction.setObjectName("about")
        self.aboutQtAction = QAction(MainWindow)
        self.aboutQtAction.setText(self.tr("About Qt"))
        self.aboutQtAction.setObjectName("about_qt")
        self.openAction = QAction(MainWindow)
        self.openAction.setText(self.tr("&Open"))
        self.openAction.setShortcut('Ctrl+O')
        self.openAction.setStatusTip(self.tr('Open a file'))
        self.openAction.setObjectName("open")
        self.openUrlAction = QAction(MainWindow)
        self.openUrlAction.setText(self.tr("Open &url"))
        self.openUrlAction.setShortcut('Ctrl+U')
        self.openUrlAction.setStatusTip(self.tr('Open a file with url'))
        self.saveAction = QAction(MainWindow)
        self.saveAction.setText(self.tr("&Save"))
        self.saveAction.setShortcut('Ctrl+S')
        self.saveAction.setStatusTip(self.tr('Save a file'))
        self.saveAction.setObjectName("save")
        self.saveAsAction = QAction(MainWindow)
        self.saveAsAction.setText(self.tr("Save As"))
        self.saveAsAction.setObjectName("save_as")
        self.closeAction = QAction(MainWindow)
        self.closeAction.setText(self.tr("&Close"))
        self.closeAction.setShortcut('Ctrl+W')
        self.closeAction.setStatusTip(self.tr('Close current page'))
        self.exitAction = QAction(MainWindow)
        self.exitAction.setText(self.tr("&Exit"))
        self.exitAction.setShortcut('Ctrl+Q')
        self.exitAction.setStatusTip(self.tr('Exit application'))
        self.settingAction = QAction(MainWindow)
        self.settingAction.setText(self.tr("&Settings"))
        self.settingAction.setShortcut('Ctrl+P')
        self.settingAction.setStatusTip(self.tr('Open settings dialog'))

        self.helpMenu.addAction(self.aboutAction)
        self.helpMenu.addAction(self.aboutQtAction)
        self.toolMenu.addAction(self.settingAction)
        self.fileMenu.addAction(self.openAction)
        self.fileMenu.addAction(self.openUrlAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.saveAction)
        self.fileMenu.addAction(self.saveAsAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.closeAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAction)

        # Signal & Slot
        self.addButton.clicked.connect(self.addRowSlot)
        self.delButton.clicked.connect(self.delRowSlot)
        self.upButton.clicked.connect(self.moveRowSlot)
        self.downButton.clicked.connect(self.moveRowSlot)
        self.checkButton.clicked.connect(self.checkUpdateSlot)
        self.updateButton.clicked.connect(self.updateTableItemSlot)
        self.editRuleButton.clicked.connect(self.editTableItemRuleSlot)
        self.settingAction.triggered.connect(self.showSettingDialogSlot)
        self.aboutAction.triggered.connect(self.showAboutDialogSlot)
        self.aboutQtAction.triggered.connect(self.showAboutDialogSlot)
        self.openAction.triggered.connect(self.showFileDialogSlot)
        self.openUrlAction.triggered.connect(self.showOpenUrlDialogSlot)
        self.saveAction.triggered.connect(self.showFileDialogSlot)
        self.saveAsAction.triggered.connect(self.showFileDialogSlot)
        self.closeAction.triggered.connect(self.tableWidget.clearContents)
        self.exitAction.triggered.connect(self.close)
        self.tableWidget.itemChanged.connect(self.itemChangedSlot)
        self.tableWidget.itemClicked.connect(self.itemClickedForOpenUrlSlot)

    def closeEvent(self, event):
        """关闭应用提示"""
        reply = QMessageBox.question(self, self.tr('Message'),
            self.tr("Are you sure to quit?"), QMessageBox.Yes |
            QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()  # 接受关闭事件
        else:
            event.ignore()  # 拒绝关闭事件

    def itemClickedForOpenUrlSlot(self, item):
        """Ctrl+left 打开链接"""
        # http://stackoverflow.com/questions/3100090/
        if item.column() == 1 and item.text() and \
                qApp.keyboardModifiers() == Qt.ControlModifier:
            QDesktopServices.openUrl(QUrl(item.text()))  # open url

    def itemChangedSlot(self, item):  # QTableWidgetItem
        """捕获itemChanged信号, 修改表项"""
        try:
            self.tableContents[item.row()].load(item.column(), item.text())
        except IndexError:
            pass

    def moveRowSlot(self):
        """移动行"""
        try:
            sourceRow = self.tableWidget.currentRow()
            destRow = sourceRow-1 if self.sender().objectName() == "up" else sourceRow+1
            if sourceRow != -1:
                sourceItems = self.getRow(sourceRow)
                destItems = self.getRow(destRow)
                self.setRow(destRow, sourceItems)
                self.setRow(sourceRow, destItems)
                self.tableWidget.selectRow(destRow)  # 修改焦点
                log.debug(self.tableContents)
        except AttributeError:
            if self.sender().objectName() == "up":
                QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is to top."))
            else:
                QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is to bottom."))

    def getRow(self, rowIndex):
        """获取行"""
        rowItems = []
        for i in range(7):
            item = self.tableWidget.item(rowIndex, i)
            rowItems.append(item.text())
        rowItems.append(self.tableContents[rowIndex].get_rules(ui=True))
        return rowItems

    def setRow(self, rowIndex, rowItems):
        """设置行"""
        for n, i in enumerate(rowItems):
            if n == len(rowItems) - 1:
                self.tableContents[rowIndex].set_rules(i)
            else:
                item = self.tableWidget.item(rowIndex, n)
                item.setText(i)

    def addRowSlot(self):
        """添加行"""
        rowIndex = self.tableWidget.rowCount()
        self.tableWidget.setRowCount(rowIndex + 1)
        self.tableContents.append(Checker())
        self.updateTableSlot(0)  # 更新列表控件
        log.debug(self.tableContents)

    def delRowSlot(self):
        """删除行"""
        # 焦点默认在第一行,要设置setFocusPolicy(Qt.NoFocus)
        rowIndex = self.tableWidget.currentRow()
        if rowIndex != -1:
            self.tableWidget.removeRow(rowIndex)
            self.tableContents.remove(self.tableContents[rowIndex])
            log.debug(self.tableContents)
        else:
            QMessageBox.warning(self, self.tr("Warning"), self.tr("Please select a row."))

    def loadData(self, data):
        """载入数据"""
        self.tableContents = []  # list.clear() Python 3
        for i in data:
            self.tableContents.append(Checker(i))

    def checkUpdateSlot(self):
        """执行更新检查"""
        self.wtime[0] = int(time.time())  # 计时
        self.statusbar.showMessage(self.tr("checking..."))
        self.progressBar.setValue(0)
        self.progressBar.show()
        self.progressVal = 0
        self.taskVal = 0

        for t in range(self.workerCount):
            t = WorkThread(self.q)  # 耗时任务需要用线程执行,再刷新进度条
            t.triggered.connect(self.updateTableSlot)
            self.workers.append(t)
            t.start()  # 执行工作线程

        # 填充队列
        for item in self.tableContents:
            self.q.put(item)

    def updateTableSlot(self, val):
        """线程通过该槽,刷新进度条,表格内容"""
        if val:
            self.taskVal += val
            self.progressVal = self.taskVal / len(self.tableContents) * 100
            self.progressBar.setValue(self.progressVal)
            self.label.setText("%s/%s" % (self.taskVal, len(self.tableContents)))
        self.tableWidget.setRowCount(len(self.tableContents))  # 行数

        for n, i in enumerate(self.tableContents):
            items = i.dump()
            for j in range(self.tableWidget.columnCount()):
                item = QTableWidgetItem(items[j])
                if j in [0, 1]:
                    item.setToolTip(item.text())
                self.tableWidget.setItem(n, j, item)
            self.setStatusColor(n)

        self.setBackgroundColor(self.bgColor)

        if self.progressVal == 100:
            self.wtime[1] = int(time.time())
            self.statusbar.showMessage(self.tr(
                "finished (work time %ds)") % (self.wtime[1] - self.wtime[0]))

    def updateTableItemSlot(self):
        """更新指定的 RPM 日期为 Release 日期"""
        rowIndex = self.tableWidget.currentRow()
        if rowIndex != -1:
            try:
                item = self.tableWidget.item(rowIndex, 4)
                self.tableWidget.item(rowIndex, 3).setText(item.text())
                self.tableContents[rowIndex].load_meta(item.text())
            except (IndexError, AttributeError):
                QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is empty."))
        else:
            QMessageBox.warning(self, self.tr("Warning"), self.tr("Please select a row."))

    def editTableItemRuleSlot(self):
        """编辑列表项规则"""
        rowIndex = self.tableWidget.currentRow()
        if rowIndex != -1:
            try:
                # 父控件, 标题, 标签提示, 默认值, window flags
                rules, ok = QInputDialog.getMultiLineText(self, self.tr("Edit rule"),
                    self.tr("XPath rule(format: \"[(time, commit), (time, commit)]\"):"),
                    re.sub("\),|],|',", lambda x: "%s\n" % x.group(),
                        str(self.tableContents[rowIndex].get_rules(ui=True)) ))

                if ok:
                    self.tableContents[rowIndex].set_rules(rules)
            except (IndexError, UnboundLocalError):
                QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is empty."))
        else:
            QMessageBox.warning(self, self.tr("Warning"), self.tr("Please select a row."))

    def showSettingDialogSlot(self):
        """显示设置对话框"""
        settingDialog = SettingDialog()
        settingDialog.exec_()

    def showAboutDialogSlot(self):
        """显示关于对话框"""
        if self.sender().objectName() == "about":
            QMessageBox.about(self, self.tr("Checker"), self.description)
        else:
            QMessageBox.aboutQt(self, self.tr("Checker"))

    def showOpenUrlDialogSlot(self):
        """通过 Url 打开文件"""
        url, _ = QInputDialog.getText(self, self.tr("Open url"),
                     self.tr("Enter url:"), QLineEdit.Normal, "")
        try:
            resp = backend.get(url)
            self.loadData(resp.json())
            self.updateTableSlot(0)  # 更新列表控件
            self.statusbar.showMessage(self.tr("open url successfully"))
        except Exception as e:
            QMessageBox.warning(self, self.tr("Error"),
                                self.tr("Open url failed. See below:\n%s") % e)
            self.statusbar.showMessage(self.tr("open url failed"))

    def loadCsvFile(self, fname):
        """load csv file (old format)"""
        _data = []
        with open(fname, 'r') as fp:
            content = csv.reader(fp)
            for row in content:
                if len(row) and row[0][0] != "#":
                    _data.append(row)
            self.loadData(_data)

    def showFileDialogSlot(self):
        """打开/保存数据至文件"""
        if self.sender().objectName() == "open":
            fname = QFileDialog.getOpenFileName(self, self.tr("Open file"), os.getcwd())
            fname = fname[0] if isinstance(fname, tuple) else fname  # qt5 tuple, qt4 str

            if fname:
                try:
                    with open(fname, 'r') as fp:
                        self.loadData(json.load(fp))
                except AttributeError as e:
                    QMessageBox.warning(self, self.tr("Error"),
                        self.tr("Open file failed. See below:\n%s") % e)
                except:  # json.decoder.JSONDecodeError Python 3
                    try:  # load csv file (old format)
                        self.loadCsvFile(fname)
                    except Exception as e:
                        QMessageBox.warning(self, self.tr("Error"),
                            self.tr("The file does not contain JSON or CSV. See below:\n%s") % e)

                self.updateTableSlot(0)  # 更新列表控件
                self.statusbar.showMessage(self.tr("open file successfully"))

        elif self.sender().objectName() in ["save", "save_as"]:
            fname = QFileDialog.getSaveFileName(self, self.tr("Save file"), os.getcwd())
            fname = fname[0] if isinstance(fname, tuple) else fname  # qt5 tuple, qt4 str

            if fname:
                try:
                    with open(fname, 'w') as fp:
                        json.dump([i.dump(mode="raw") for i in self.tableContents],
                                  fp, ensure_ascii=False)
                    self.statusbar.showMessage(self.tr("saved successfully"))
                except AttributeError as e:
                    QMessageBox.warning(self, self.tr("Error"),
                        self.tr("Save file failed. See below:\n%s") % e)

    def setBackgroundColor(self, color):
        """修改背景色"""
        for i in range(self.tableWidget.rowCount()):
            if i % 2 != 0:
                for j in range(self.tableWidget.columnCount()):
                    item = self.tableWidget.item(i, j)
                    if item:
                        item.setBackground(color)

    def setStatusColor(self, rowIndex):
        """修改状态文字颜色"""
        item = self.tableWidget.item(rowIndex, 6)
        if item.text() == "normal":
            item.setForeground(Qt.darkGreen)
        elif item.text() == "update":
            item.setForeground(Qt.darkRed)
        elif item.text() == "error":
            item.setForeground(Qt.darkYellow)
        elif item.text() == "none":
            item.setForeground(Qt.gray)

    def setupTable(self):
        """初始化列表"""
        self.tableWidget.setFocusPolicy(Qt.NoFocus)  # 无焦点
        self.tableWidget.setGridStyle(Qt.DashDotLine)  # 线类型
        self.tableWidget.setWordWrap(True)
        self.tableWidget.setCornerButtonEnabled(True)
        self.tableWidget.horizontalHeader().setVisible(True)  # 显示表头
        #self.tableWidget.horizontalHeader().setSortIndicatorShown(True)  # 排序指示器
        self.tableWidget.horizontalHeader().setStretchLastSection(True)  # 扩展最后一列

        self.tableWidget.setColumnCount(self.tableColumnCount)  # 列数
        self.tableWidget.setRowCount(self.tableRowCount)  # 行数

        # 行头
        for i in range(self.tableRowCount):
            item = QTableWidgetItem("%s" % (i+1))
            self.tableWidget.setVerticalHeaderItem(i, item)  # 行号

        # 列头
        for i in range(self.tableColumnCount):
            item = QTableWidgetItem(self.tableHeaders[i])  # QIcon, str
            self.tableWidget.setHorizontalHeaderItem(i, item)  # 初始化表头

        for i in [3, 4, 5]:
            self.tableWidget.resizeColumnToContents(i)  # 根据内容调整列宽

        # 初始化项目
        for i in range(self.tableRowCount):
            self.tableContents.append(Checker())
            for j in range(self.tableColumnCount):
                item = QTableWidgetItem()
                self.tableWidget.setItem(i, j, item)

        self.setBackgroundColor(self.bgColor)
Ejemplo n.º 23
0
class UpdateCheck(QDialog, Logger):
    url = "https://electrum.org/version"
    download_url = "https://electrum.org/#download"

    VERSION_ANNOUNCEMENT_SIGNING_KEYS = (
        "13xjmVAB1EATPP8RshTE8S8sNwwSUM9p1P",  # ThomasV (since 3.3.4)
        "1Nxgk6NTooV4qZsX5fdqQwrLjYcsQZAfTg",  # ghost43 (since 4.1.2)
    )

    def __init__(self, *, latest_version=None):
        QDialog.__init__(self)
        self.setWindowTitle('Electrum - ' + _('Update Check'))
        self.content = QVBoxLayout()
        self.content.setContentsMargins(*[10] * 4)

        self.heading_label = QLabel()
        self.content.addWidget(self.heading_label)

        self.detail_label = QLabel()
        self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.detail_label.setOpenExternalLinks(True)
        self.content.addWidget(self.detail_label)

        self.pb = QProgressBar()
        self.pb.setMaximum(0)
        self.pb.setMinimum(0)
        self.content.addWidget(self.pb)

        versions = QHBoxLayout()
        versions.addWidget(
            QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION))))
        self.latest_version_label = QLabel(_("Latest version: {}".format(" ")))
        versions.addWidget(self.latest_version_label)
        self.content.addLayout(versions)

        self.update_view(latest_version)

        self.update_check_thread = UpdateCheckThread()
        self.update_check_thread.checked.connect(self.on_version_retrieved)
        self.update_check_thread.failed.connect(self.on_retrieval_failed)
        self.update_check_thread.start()

        close_button = QPushButton(_("Close"))
        close_button.clicked.connect(self.close)
        self.content.addWidget(close_button)
        self.setLayout(self.content)
        self.show()

    def on_version_retrieved(self, version):
        self.update_view(version)

    def on_retrieval_failed(self):
        self.heading_label.setText('<h2>' + _("Update check failed") + '</h2>')
        self.detail_label.setText(
            _("Sorry, but we were unable to check for updates. Please try again later."
              ))
        self.pb.hide()

    @staticmethod
    def is_newer(latest_version):
        return latest_version > StrictVersion(version.ELECTRUM_VERSION)

    def update_view(self, latest_version=None):
        if latest_version:
            self.pb.hide()
            self.latest_version_label.setText(
                _("Latest version: {}".format(latest_version)))
            if self.is_newer(latest_version):
                self.heading_label.setText(
                    '<h2>' + _("There is a new update available") + '</h2>')
                url = "<a href='{u}'>{u}</a>".format(
                    u=UpdateCheck.download_url)
                self.detail_label.setText(
                    _("You can download the new version from {}.").format(url))
            else:
                self.heading_label.setText('<h2>' + _("Already up to date") +
                                           '</h2>')
                self.detail_label.setText(
                    _("You are already on the latest version of Electrum."))
        else:
            self.heading_label.setText('<h2>' + _("Checking for updates...") +
                                       '</h2>')
            self.detail_label.setText(
                _("Please wait while Electrum checks for available updates."))
Ejemplo n.º 24
0
class TabGovernance_gui(QWidget):
    def __init__(self, caller, *args, **kwargs):
        QWidget.__init__(self)
        self.caller = caller
        self.initLayout()
        self.loadIcons()
        self.refreshProposals_btn.setIcon(self.refresh_icon)
        self.budgetProjection_btn.setIcon(self.list_icon)
        self.timeIconLabel.setPixmap(
            self.time_icon.scaledToHeight(20, Qt.SmoothTransformation))
        self.questionLabel.setPixmap(
            self.question_icon.scaledToHeight(15, Qt.SmoothTransformation))
        self.loadCacheData()

    def initLayout(self):
        layout = QVBoxLayout(self)

        #  -- ROW 1
        row = QHBoxLayout()
        self.budgetProjection_btn = QPushButton()
        self.budgetProjection_btn.setToolTip("Check Budget Projection...")
        row.addWidget(self.budgetProjection_btn)
        self.selectMN_btn = QPushButton("Select Masternodes...")
        row.addWidget(self.selectMN_btn)
        self.selectedMNlabel = QLabel(
            "<em>0 masternodes selected for voting</em")
        row.addWidget(self.selectedMNlabel)
        row.addStretch(1)
        self.statusLabel = QLabel("")
        self.statusLabel.setMinimumWidth(116)
        self.resetStatusLabel('<b style="color:red">Reload Proposals</b>')
        row.addWidget(self.statusLabel)
        row.addStretch(1)
        self.mnCountLabel = QLabel()
        row.addWidget(self.mnCountLabel)
        self.refreshProposals_btn = QPushButton()
        self.refreshProposals_btn.setToolTip("Refresh Proposal List")
        row.addWidget(self.refreshProposals_btn)
        self.toggleExpiring_btn = QPushButton("Hide Expiring")
        self.toggleExpiring_btn.setToolTip(
            "Hide expiring proposals (yellow background) from list")
        row.addWidget(self.toggleExpiring_btn)
        layout.addLayout(row)

        #  -- ROW 2
        self.proposalBox = QTableWidget()
        self.proposalBox.setMinimumHeight(280)
        self.proposalBox.setSelectionMode(QAbstractItemView.MultiSelection)
        self.proposalBox.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.proposalBox.setShowGrid(True)
        self.proposalBox.setColumnCount(8)
        self.proposalBox.setRowCount(0)
        self.proposalBox.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.Stretch)
        self.proposalBox.setSortingEnabled(True)
        # self.proposalBox.verticalHeader().hide
        self.setProposalBoxHeader()
        self.proposalBox.setColumnWidth(1, 50)
        self.proposalBox.setColumnWidth(2, 50)
        self.proposalBox.setColumnWidth(3, 100)
        self.proposalBox.setColumnWidth(4, 100)
        self.proposalBox.setColumnWidth(5, 150)
        self.proposalBox.setColumnWidth(6, 120)
        self.proposalBox.setColumnWidth(7, 50)
        layout.addWidget(self.proposalBox)

        #  -- ROW 3
        row = QHBoxLayout()
        self.timeIconLabel = QLabel()
        self.timeIconLabel.setToolTip(
            "Check to add a randomized time offset (positive or negative) to enhance privacy"
        )
        row.addWidget(self.timeIconLabel)
        self.randomDelayCheck = QCheckBox()
        self.randomDelayCheck.setToolTip(
            "Check to add a randomized time offset when voting (max +5/-5 hrs)"
        )
        row.addWidget(self.randomDelayCheck)
        self.randomDelayNeg_edt = QSpinBox()
        self.randomDelayNeg_edt.setPrefix('- ')
        self.randomDelayNeg_edt.setSuffix(" secs")
        self.randomDelayNeg_edt.setToolTip(
            "Maximum random time (in seconds) subtracted from each vote timestamp"
        )
        self.randomDelayNeg_edt.setFixedWidth(100)
        self.randomDelayNeg_edt.setMaximum(18000)
        self.randomDelayNeg_edt.setValue(0)
        row.addWidget(self.randomDelayNeg_edt)
        self.randomDelayPos_edt = QSpinBox()
        self.randomDelayPos_edt.setPrefix("+ ")
        self.randomDelayPos_edt.setSuffix(" secs")
        self.randomDelayPos_edt.setToolTip(
            "Maximum random time (in seconds) added to each vote timestamp")
        self.randomDelayPos_edt.setFixedWidth(100)
        self.randomDelayPos_edt.setMaximum(18000)
        self.randomDelayPos_edt.setValue(300)
        row.addWidget(self.randomDelayPos_edt)
        row.addStretch(1)
        self.loadingLine = QLabel(
            "<b style='color:red'>Vote Signatures.</b> Completed: ")
        self.loadingLinePercent = QProgressBar()
        self.loadingLinePercent.setMaximumWidth(200)
        self.loadingLinePercent.setMaximumHeight(10)
        self.loadingLinePercent.setRange(0, 100)
        row.addWidget(self.loadingLine)
        row.addWidget(self.loadingLinePercent)
        self.loadingLine.hide()
        self.loadingLinePercent.hide()
        row.addStretch(1)
        self.selectedPropLabel = QLabel("<em>0 proposals selected</em>")
        row.addWidget(self.selectedPropLabel)
        self.questionLabel = QLabel()
        message = "Refresh proposals.\n"
        message += "GREEN: proposal passing\n"
        message += "WHITE: missing votes in order to pass\n"
        message += "RED: proposal not passing\n"
        message += "YELLOW: proposal expiring (last payment block)\n"
        self.questionLabel.setToolTip(message)
        row.addWidget(self.questionLabel)
        layout.addLayout(row)

        #  -- ROW 4
        row = QHBoxLayout()
        self.voteYes_btn = QPushButton("Vote YES")
        self.voteYes_btn.setToolTip("Vote YES on selected proposals")
        row.addWidget(self.voteYes_btn)
        self.voteAbstain_btn = QPushButton("Vote ABSTAIN")
        self.voteAbstain_btn.setToolTip(
            "Vote ABSTAIN on selected proposals [currently disabled]")
        row.addWidget(self.voteAbstain_btn)
        self.voteNo_btn = QPushButton("Vote NO")
        self.voteNo_btn.setToolTip("Vote NO on selected proposals")
        row.addWidget(self.voteNo_btn)
        layout.addLayout(row)

    def loadCacheData(self):
        if self.caller.parent.cache.get("votingDelayCheck"):
            negative_delay = self.caller.parent.cache.get("votingDelayNeg")
            positive_delay = self.caller.parent.cache.get("votingDelayPos")
            self.randomDelayCheck.setChecked(True)
            self.randomDelayNeg_edt.setValue(negative_delay)
            self.randomDelayPos_edt.setValue(positive_delay)

    def setProposalBoxHeader(self):
        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("Name")
        item.setToolTip("Proposal Name")
        self.proposalBox.setHorizontalHeaderItem(0, item)

        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("Hash")
        item.setToolTip("Proposal Hash")
        self.proposalBox.setHorizontalHeaderItem(1, item)

        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("Link")
        item.setToolTip("Link to Proposal Thread")
        self.proposalBox.setHorizontalHeaderItem(2, item)

        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("PIV/month")
        item.setToolTip("Monthly PIV Payment requested")
        self.proposalBox.setHorizontalHeaderItem(3, item)

        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("Payments")
        item.setToolTip("Remaining Payment Count / Total Payment Count")
        self.proposalBox.setHorizontalHeaderItem(4, item)

        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("Network Votes")
        item.setToolTip("Network Votes: YEAS/ABSTAINS/NAYS")
        self.proposalBox.setHorizontalHeaderItem(5, item)

        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("My Votes")
        item.setToolTip("My Votes: YEAS/ABSTAINS/NAYS")
        self.proposalBox.setHorizontalHeaderItem(6, item)

        item = QTableWidgetItem()
        item.setTextAlignment(Qt.AlignCenter)
        item.setText("Details")
        item.setToolTip("Check Proposal Details")
        self.proposalBox.setHorizontalHeaderItem(7, item)

    def loadIcons(self):
        self.refresh_icon = QIcon(
            os.path.join(self.caller.imgDir, 'icon_refresh.png'))
        self.time_icon = QPixmap(
            os.path.join(self.caller.imgDir, 'icon_clock.png'))
        self.link_icon = QIcon(
            os.path.join(self.caller.imgDir, 'icon_link.png'))
        self.search_icon = QIcon(
            os.path.join(self.caller.imgDir, 'icon_search.png'))
        self.list_icon = QIcon(
            os.path.join(self.caller.imgDir, 'icon_list.png'))
        self.question_icon = QPixmap(
            os.path.join(self.caller.imgDir, 'icon_question.png'))

    def resetStatusLabel(self, message=None):
        if message is None:
            self.statusLabel.setText(
                '<em><b style="color:purple">Loading proposals...</b></em>')
        else:
            self.statusLabel.setText(message)
        self.statusLabel.setVisible(True)
Ejemplo n.º 25
0
class GeoToolsDownloadManager(QWidget):
    def __init__(self, iface) -> None:
        super().__init__()

        self.options = get_options()
        self.msg_bar = MessageBar(iface)

        self.tree_widget = QTreeWidget()
        self.populate_tree()

        self.select_mandatory_hires_button = QPushButton(
            'Select Mandatory Fields in Highest Resolution')
        self.select_mandatory_hires_button.clicked.connect(
            self.on_select_mandatory_hires_button_clicked)

        self.select_mandatory_lores_button = QPushButton(
            'Select Mandatory Fields in Lowest Resolution')
        self.select_mandatory_lores_button.clicked.connect(
            self.on_select_mandatory_lores_button_clicked)

        self.download_button = QPushButton('Download Selected Datasets')
        self.download_button.clicked.connect(self.on_download_button_clicked)

        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, PROGRESS_BAR_MAX)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.hide()

        vbox = QVBoxLayout()
        vbox.addWidget(self.tree_widget)
        vbox.addWidget(self.select_mandatory_hires_button)
        vbox.addWidget(self.select_mandatory_lores_button)
        vbox.addWidget(self.download_button)
        vbox.addWidget(self.progress_bar)
        self.setLayout(vbox)

    def populate_tree(self) -> None:
        self.tree_widget.setHeaderLabels(['ID', 'Resolution', 'Description'])
        self.tree_widget.setRootIsDecorated(False)
        self.tree_widget.setSortingEnabled(True)
        self.tree_widget.sortByColumn(0, Qt.AscendingOrder)
        header = self.tree_widget.header()
        header.setSectionsMovable(False)
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QHeaderView.Stretch)

        for dataset_id, (description, resolution) in geo_datasets.items():
            item = QTreeWidgetItem(self.tree_widget)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)

            item.setText(0, dataset_id)
            item.setData(0, Qt.UserRole, dataset_id)
            item.setCheckState(0, Qt.Unchecked)
            if is_geo_dataset_downloaded(dataset_id, self.options.geog_dir):
                item.setFlags(Qt.NoItemFlags)
                item.setToolTip(
                    0, 'Dataset downloaded in: {}'.format(
                        get_geo_dataset_path(dataset_id,
                                             self.options.geog_dir)))
            else:
                item.setToolTip(0, dataset_id)

            if isinstance(resolution, str):
                item.setText(1, resolution)
            else:
                item.setText(1, formatted_dd_to_dms(resolution))
                item.setToolTip(1, '{}°'.format(resolution))

            item.setText(2, description)
            item.setToolTip(2, description)

    def on_select_mandatory_lores_button_clicked(self):
        self.select_datasets(geo_datasets_mandatory_lores)

    def on_select_mandatory_hires_button_clicked(self):
        self.select_datasets(geo_datasets_mandatory_hires)

    def select_datasets(self, names: List[str]) -> None:
        items = self.get_items()
        for name, item in items.items():
            item.setCheckState(0,
                               Qt.Checked if name in names else Qt.Unchecked)

    def get_items(self) -> Dict[str, QTreeWidgetItem]:
        items = {}  # type: Dict[str,QTreeWidgetItem]
        for index in range(self.tree_widget.topLevelItemCount()):
            item = self.tree_widget.topLevelItem(index)
            items[item.data(0, Qt.UserRole)] = item
        return items

    def on_download_button_clicked(self) -> None:
        datasets_to_download = []
        for name, item in self.get_items().items():
            if item.checkState(0) == Qt.Checked:
                datasets_to_download.append(name)

        thread = TaskThread(
            lambda: self.download_datasets(datasets_to_download),
            yields_progress=True)
        thread.started.connect(self.on_started_download)
        thread.progress.connect(self.on_progress_download)
        thread.finished.connect(self.on_finished_download)
        thread.succeeded.connect(self.on_successful_download)
        thread.failed.connect(reraise)
        thread.start()

    def on_started_download(self):
        self.download_button.hide()
        self.progress_bar.show()
        self.tree_widget.setEnabled(False)

    def on_progress_download(self, progress: float, status: str) -> None:
        bar_value = int(progress * PROGRESS_BAR_MAX)
        self.progress_bar.setValue(bar_value)
        self.progress_bar.repaint()  # otherwise just updates in 1% steps
        logger.debug(f'Geo data download: {progress*100:.1f}% - {status}')

    def on_finished_download(self) -> None:
        self.download_button.show()
        self.progress_bar.hide()
        self.tree_widget.setEnabled(True)
        self.tree_widget.clear()
        self.populate_tree()
        Broadcast.geo_datasets_updated.emit()

    def on_successful_download(self) -> None:
        self.msg_bar.success('Geographical datasets downloaded successfully.')

    def download_datasets(
            self, dataset_names: List[str]) -> Iterable[Tuple[float, str]]:
        yield 0.0, 'selected: ' + ', '.join(dataset_names)
        for i, name in enumerate(dataset_names):
            for dataset_progress in download_and_extract_geo_dataset(
                    name, self.options.geog_dir):
                total_progress = (i + dataset_progress) / len(dataset_names)
                yield total_progress, f'downloading {name} ({dataset_progress*100:.1f}%)'
Ejemplo n.º 26
0
class NTFSLogFileDialog(QDialog, QObject):
    complete = pyqtSignal()

    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        QObject.__init__(self)
        self.selected_partition = -1
        self.ui()

    def ui(self):
        self.setWindowTitle("Import File System Log File")
        self.setFixedSize(self.sizeHint())
        self.layout = QBoxLayout(QBoxLayout.TopToBottom, self)
        spacer_item1 = QSpacerItem(10, 5)
        self.layout.addItem(spacer_item1)
        self.setLayout(self.layout)

        # First Group
        self.disk_raw_chk_box = QCheckBox(
            "In this case, it's possible to carve some files.", self)
        self.disk_raw_chk_box.stateChanged.connect(
            lambda: self.select_type(self.disk_raw_chk_box))
        self.disk_raw_group_box = QGroupBox(self)
        self.disk_raw_group_box.setStyleSheet("margin-top: 0;")
        self.disk_raw_group_box.setDisabled(True)
        disk_raw_group_box_layout = QHBoxLayout(self.disk_raw_group_box)
        self.disk_raw_group_box.setLayout(disk_raw_group_box_layout)

        self.disk_raw_label = QLabel("Disk Raw: ", self)
        self.disk_raw_text_box = QLineEdit()
        self.disk_raw_text_box.setReadOnly(True)
        self.disk_raw_text_box.setFixedWidth(400)

        self.browse_disk_raw_btn = QPushButton("...", self)
        self.browse_disk_raw_btn.setFixedWidth(50)
        self.browse_disk_raw_btn.clicked.connect(self.btn_clicekd)
        self.browse_disk_raw_btn.setCursor(QCursor(Qt.PointingHandCursor))

        disk_raw_group_box_layout.addWidget(self.disk_raw_label)
        disk_raw_group_box_layout.addWidget(self.disk_raw_text_box)
        disk_raw_group_box_layout.addWidget(self.browse_disk_raw_btn)

        self.layout.addWidget(self.disk_raw_chk_box)
        self.layout.addWidget(self.disk_raw_group_box)

        # Second Group
        self.ntfs_log_file_chk_box = QCheckBox(
            "In this case, NTFS Log analysis only supported.", self)
        self.ntfs_log_file_chk_box.stateChanged.connect(
            lambda: self.select_type(self.ntfs_log_file_chk_box))

        self.ntfs_log_group_box = QGroupBox(self)
        self.ntfs_log_group_box.setStyleSheet("margin-top: 0;")
        self.ntfs_log_group_box.setDisabled(True)
        ntfs_log_group_box_layout = QGridLayout(self)
        self.ntfs_log_group_box.setLayout(ntfs_log_group_box_layout)

        self.mft_label = QLabel("$MFT: ", self)
        self.mft_path_text_box = QLineEdit(self)
        self.mft_path_text_box.setReadOnly(True)
        self.mft_path_text_box.setFixedWidth(400)
        self.browse_mft_btn = QPushButton("...", self)
        self.browse_mft_btn.setFixedWidth(50)
        self.browse_mft_btn.clicked.connect(self.btn_clicekd)
        self.browse_mft_btn.setCursor(QCursor(Qt.PointingHandCursor))

        self.usnjrnl_label = QLabel("$UsnJrnl: ", self)
        self.usnjrnl_path_text_box = QLineEdit(self)
        self.usnjrnl_path_text_box.setReadOnly(True)
        self.usnjrnl_path_text_box.setFixedWidth(400)
        self.browse_usnjrnl_btn = QPushButton("...", self)
        self.browse_usnjrnl_btn.setFixedWidth(50)
        self.browse_usnjrnl_btn.clicked.connect(self.btn_clicekd)
        self.browse_usnjrnl_btn.setCursor(QCursor(Qt.PointingHandCursor))

        self.logfile_label = QLabel("$LogFile: ", self)
        self.logfile_path_text_box = QLineEdit(self)
        self.logfile_path_text_box.setReadOnly(True)
        self.logfile_path_text_box.setFixedWidth(400)
        self.browse_logfile_btn = QPushButton("...", self)
        self.browse_logfile_btn.setFixedWidth(50)
        self.browse_logfile_btn.clicked.connect(self.btn_clicekd)
        self.browse_logfile_btn.setCursor(QCursor(Qt.PointingHandCursor))

        ntfs_log_group_box_layout.addWidget(self.mft_label, 0, 0)
        ntfs_log_group_box_layout.addWidget(self.mft_path_text_box, 0, 1)
        ntfs_log_group_box_layout.addWidget(self.browse_mft_btn, 0, 2)
        ntfs_log_group_box_layout.addWidget(self.usnjrnl_label, 1, 0)
        ntfs_log_group_box_layout.addWidget(self.usnjrnl_path_text_box, 1, 1)
        ntfs_log_group_box_layout.addWidget(self.browse_usnjrnl_btn, 1, 2)
        ntfs_log_group_box_layout.addWidget(self.logfile_label, 2, 0)
        ntfs_log_group_box_layout.addWidget(self.logfile_path_text_box, 2, 1)
        ntfs_log_group_box_layout.addWidget(self.browse_logfile_btn, 2, 2)

        self.submit_btn = QPushButton("Submit", self)
        self.submit_btn.setFixedSize(100, 40)
        self.submit_btn.setCursor(QCursor(Qt.PointingHandCursor))

        self.logging_label = QLabel("Loading...", self)
        self.logging_label.setFixedHeight(20)
        self.logging_label.setAlignment(Qt.AlignCenter)
        self.logging_label.hide()

        self.loading_bar = QProgressBar(self)
        self.loading_bar.setFixedHeight(10)
        self.loading_bar.setTextVisible(False)
        self.loading_bar.hide()

        self.bar_thread = LoadingBarThread(self)
        self.bar_thread.change_value.connect(self.loading_bar.setValue)

        self.spacer_item2 = QSpacerItem(10, 15)
        self.spacer_item3 = QSpacerItem(10, 20)
        self.layout.addItem(self.spacer_item2)
        self.layout.addWidget(self.ntfs_log_file_chk_box)
        self.layout.addWidget(self.ntfs_log_group_box)
        self.layout.addItem(self.spacer_item3)
        self.layout.addWidget(self.submit_btn, alignment=Qt.AlignHCenter)

        # self.setWindowModality(Qt.WindowModal)
        self.setWindowFlag(Qt.WindowCloseButtonHint | Qt.WindowModal)
        self.show()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.close()

    def select_type(self, b):
        if b is self.disk_raw_chk_box:
            if b.isChecked():
                self.ntfs_log_file_chk_box.setChecked(False)
                self.ntfs_log_group_box.setDisabled(True)
                self.disk_raw_group_box.setDisabled(False)
            else:
                self.disk_raw_group_box.setDisabled(True)
        else:
            if b.isChecked():
                self.disk_raw_chk_box.setChecked(False)
                self.disk_raw_group_box.setDisabled(True)
                self.ntfs_log_group_box.setDisabled(False)
            else:
                self.ntfs_log_group_box.setDisabled(True)

    def btn_clicekd(self):
        sender = self.sender()
        fileName = QFileDialog.getOpenFileName(self)
        if sender is self.browse_disk_raw_btn:
            self.disk_raw_text_box.setText(fileName[0])
        elif sender is self.browse_mft_btn:
            self.mft_path_text_box.setText(fileName[0])
        elif sender is self.browse_usnjrnl_btn:
            self.usnjrnl_path_text_box.setText(fileName[0])
        elif sender is self.browse_logfile_btn:
            self.logfile_path_text_box.setText(fileName[0])

    def ready(self):
        self.submit_btn.hide()
        self.layout.removeWidget(self.submit_btn)
        self.layout.addWidget(self.logging_label,
                              alignment=Qt.AlignBottom | Qt.AlignHCenter)
        self.layout.addWidget(self.loading_bar)
        self.logging_label.show()
        self.loading_bar.show()
        self.bar_thread.start()

    def resume(self):
        if self.bar_thread.cnt < 50:
            self.bar_thread.cnt = 100
            return
        self.bar_thread.toggle_status()

    def change_interface(self, contents):
        from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem
        self.layout.removeWidget(self.disk_raw_chk_box)
        self.disk_raw_chk_box.hide()
        self.layout.removeWidget(self.disk_raw_group_box)
        self.disk_raw_group_box.hide()
        self.layout.removeItem(self.spacer_item2)
        self.layout.removeWidget(self.ntfs_log_file_chk_box)
        self.ntfs_log_file_chk_box.hide()
        self.layout.removeWidget(self.ntfs_log_group_box)
        self.ntfs_log_group_box.hide()
        self.layout.removeItem(self.spacer_item3)
        self.layout.removeWidget(self.submit_btn)

        self.disk_name_label = QLabel("Image Name:\t" + contents[0][0], self)
        self.disk_size_label = QLabel(
            "Image Size:\t{} Bytes".format(contents[0][1]), self)
        self.disk_size_label.setFixedHeight(20)
        self.disk_size_label.setAlignment(Qt.AlignVCenter)
        self.disk_part_label = QLabel("Partition:", self)
        self.disk_part_label.setFixedHeight(20)
        self.disk_part_label.setAlignment(Qt.AlignBottom)

        self.partition_tree = QTreeWidget(self)
        self.partition_tree.setHeaderLabels([
            "Order", "File System", "Active", "Starting Offset",
            "Total Sector", "Size"
        ])
        self.partition_tree.item_changed.connect(self.item_changed)
        self.partition_tree.resizeColumnToContents(2)
        self.partition_tree.resizeColumnToContents(3)
        self.partition_tree.resizeColumnToContents(4)
        self.partition_tree.headerItem().setTextAlignment(0, Qt.AlignCenter)
        self.partition_tree.headerItem().setTextAlignment(1, Qt.AlignCenter)

        self.partition_items = []
        for row in range(1, 5):
            self.partition_tree.headerItem().setTextAlignment(
                row + 1, Qt.AlignCenter)
            item = QTreeWidgetItem(self.partition_tree)
            item.setText(0, str(row))
            item.setTextAlignment(0, Qt.AlignLeft)
            if not contents[row]:
                item.setText(1, "None")
                item.setCheckState(0, Qt.Unchecked)
                item.setDisabled(True)
                continue
            for col in range(5):
                item.setText(col + 1, contents[row][col])
                item.setTextAlignment(col + 1, Qt.AlignCenter)
            item.setTextAlignment(1, Qt.AlignLeft)
            item.setCheckState(0, Qt.Unchecked)
            self.partition_items.append(item)

        self.layout.addWidget(self.disk_name_label)
        self.layout.addWidget(self.disk_size_label)
        self.layout.addWidget(self.disk_part_label)
        self.layout.addWidget(self.partition_tree)
        self.layout.addItem(QSpacerItem(10, 10))
        self.layout.addWidget(self.submit_btn, alignment=Qt.AlignCenter)

    def item_changed(self, changed_item, p_int):
        if changed_item.checkState(0) == Qt.Checked:
            self.selected_partition = int(changed_item.text(0))
            for item in self.partition_items:
                if item is not changed_item:
                    item.setCheckState(0, Qt.Unchecked)
Ejemplo n.º 27
0
class InviteReceiverDialog(QDialog):
    done = pyqtSignal(object)  # Tahoe gateway
    closed = pyqtSignal(QWidget)

    def __init__(self, gateways):
        super(InviteReceiverDialog, self).__init__()
        self.gateways = gateways
        self.invite_receiver = None
        self.joined_folders = []

        self.setMinimumSize(500, 300)

        self.mail_closed_icon = QLabel()
        self.mail_closed_icon.setAlignment(Qt.AlignCenter)
        self.mail_closed_icon.setPixmap(Pixmap('mail-envelope-closed.png',
                                               128))

        self.mail_open_icon = QLabel()
        self.mail_open_icon.setAlignment(Qt.AlignCenter)
        self.mail_open_icon.setPixmap(Pixmap('mail-envelope-open.png', 128))

        self.folder_icon = QLabel()
        icon = QFileIconProvider().icon(QFileInfo(config_dir))
        self.folder_icon.setPixmap(icon.pixmap(128, 128))
        self.folder_icon.setAlignment(Qt.AlignCenter)

        self.invite_code_widget = InviteCodeWidget(self)
        self.invite_code_widget.lineedit.go.connect(self.go)  # XXX

        self.tor_label = QLabel()
        self.tor_label.setToolTip(
            "This connection is being routed through the Tor network.")
        self.tor_label.setPixmap(Pixmap('tor-onion.png', 24))

        self.checkmark = QLabel()
        self.checkmark.setAlignment(Qt.AlignCenter)
        self.checkmark.setPixmap(Pixmap('green_checkmark.png', 32))

        self.progressbar = QProgressBar(self)
        self.progressbar.setValue(0)
        self.progressbar.setMaximum(6)  # XXX
        self.progressbar.setTextVisible(False)

        self.message_label = QLabel(' ')
        self.message_label.setStyleSheet("color: grey")
        self.message_label.setAlignment(Qt.AlignCenter)

        self.error_label = QLabel()
        self.error_label.setStyleSheet("color: red")
        self.error_label.setAlignment(Qt.AlignCenter)

        self.close_button = QPushButton("Close")
        self.close_button.clicked.connect(self.close)

        layout = QGridLayout(self)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 0, 0)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addWidget(self.mail_closed_icon, 1, 2, 1, 3)
        layout.addWidget(self.mail_open_icon, 1, 2, 1, 3)
        layout.addWidget(self.folder_icon, 1, 2, 1, 3)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 4)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)
        layout.addWidget(self.invite_code_widget, 2, 2, 1, 3)
        layout.addWidget(self.checkmark, 2, 3, 1, 1)
        layout.addWidget(self.tor_label, 3, 1, 1, 1,
                         Qt.AlignRight | Qt.AlignVCenter)
        layout.addWidget(self.progressbar, 3, 2, 1, 3)
        layout.addWidget(self.message_label, 5, 1, 1, 5)
        layout.addWidget(self.error_label, 5, 2, 1, 3)
        layout.addWidget(self.close_button, 6, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 7, 1)

        self.reset()

    def reset(self):
        self.mail_open_icon.hide()
        self.folder_icon.hide()
        self.mail_closed_icon.show()
        self.progressbar.hide()
        self.error_label.setText('')
        self.error_label.hide()
        self.close_button.hide()
        self.tor_label.hide()
        self.checkmark.hide()
        self.progressbar.setStyleSheet('')

    def show_error(self, text):
        self.error_label.setText(text)
        self.message_label.hide()
        self.error_label.show()
        reactor.callLater(3, self.error_label.hide)
        reactor.callLater(3, self.message_label.show)

    def update_progress(self, message):
        step = self.progressbar.value() + 1
        self.progressbar.setValue(step)
        self.message_label.setText(message)
        if step == 3:
            self.mail_closed_icon.hide()
            self.mail_open_icon.show()

    def set_joined_folders(self, folders):
        self.joined_folders = folders
        if folders:
            self.mail_open_icon.hide()
            self.folder_icon.show()

    def on_got_icon(self, path):
        self.mail_open_icon.setPixmap(Pixmap(path, 128))
        self.mail_closed_icon.hide()
        self.mail_open_icon.show()

    def on_done(self, gateway):
        self.progressbar.setValue(self.progressbar.maximum())
        self.close_button.show()
        self.checkmark.show()
        self.done.emit(gateway)
        if self.joined_folders and len(self.joined_folders) == 1:
            target = self.joined_folders[0]
            self.message_label.setText(
                'Successfully joined folder "{0}"!\n"{0}" is now available '
                'for download'.format(target))
        elif self.joined_folders:
            target = humanized_list(self.joined_folders, 'folders')
            self.message_label.setText(
                'Successfully joined {0}!\n{0} are now available for '
                'download'.format(target))
        self.close()  # TODO: Cleanup

    def on_grid_already_joined(self, grid_name):
        QMessageBox.information(
            self, "Already connected",
            'You are already connected to "{}"'.format(grid_name))
        self.close()

    def got_message(self, _):
        self.update_progress("Reading invitation...")  # 3

    def got_welcome(self):
        self.update_progress("Connected; waiting for message...")  # 2

    def handle_failure(self, failure):
        logging.error(str(failure))
        if failure.type == CancelledError and self.progressbar.value() > 2:
            return
        show_failure(failure, self)
        self.close()

    def go(self, code):
        self.reset()
        self.invite_code_widget.hide()
        self.progressbar.show()
        if self.invite_code_widget.tor_checkbox.isChecked():
            use_tor = True
            self.tor_label.show()
            self.progressbar.setStyleSheet(
                'QProgressBar::chunk {{ background-color: {}; }}'.format(
                    TOR_PURPLE))
        else:
            use_tor = False
        self.update_progress("Verifying invitation...")  # 1
        self.invite_receiver = InviteReceiver(self.gateways, use_tor)
        self.invite_receiver.got_welcome.connect(self.got_welcome)
        self.invite_receiver.got_message.connect(self.got_message)
        self.invite_receiver.grid_already_joined.connect(
            self.on_grid_already_joined)
        self.invite_receiver.update_progress.connect(self.update_progress)
        self.invite_receiver.got_icon.connect(self.on_got_icon)
        self.invite_receiver.joined_folders.connect(self.set_joined_folders)
        self.invite_receiver.done.connect(self.on_done)
        d = self.invite_receiver.receive(code)
        d.addErrback(self.handle_failure)
        reactor.callLater(30, d.cancel)

    def enterEvent(self, event):
        event.accept()
        self.invite_code_widget.lineedit.update_action_button()  # XXX

    def closeEvent(self, event):
        event.accept()
        try:
            self.invite_receiver.cancel()
        except AttributeError:
            pass
        self.closed.emit(self)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
Ejemplo n.º 28
0
class PersephonepWindow(QWidget):
    def __init__(self, url):
        super(PersephonepWindow, self).__init__()
        self.setAttribute(Qt.WA_DeleteOnClose, True)

        #    def Generate(self, url):

        self.initurl = url

        # config
        # initurl = 'https://www.google.co.jp'

        # setting window
        self.window = QWebEngineView()

        #        # Set WebPage with javascript console output.
        #        self.window.setPage(WebPageWithJSConsole(self.window))
        #

        proxy = QNetworkProxy()
        proxy.setType(QNetworkProxy.NoProxy)
        QNetworkProxy.setApplicationProxy(proxy)

        # condig url
        self.window.load(QUrl(self.initurl))
        self.window.setWindowTitle(__program__)

        # setting button
        self.reload_button = QPushButton('reload')
        self.reload_button.setToolTip('Reload this page.')
        self.reload_button.clicked.connect(self.window.reload)

        ##
        ## Download dialog
        ##
        self.progress = QProgressBar(self)
        self.progress.setMaximum(100)
        self.progress.setStyleSheet(PROGRESS_STYLE)
        self.progress.hide()
        self.downloading_filename = ''
        ##
        ##

        self.url_edit = QLineEdit()
        self.url_edit.setText(self.initurl)
        self.url_edit.setReadOnly(True)
        self.url_edit.setToolTip('URL box')
        self.home_button = QPushButton('home')
        self.home_button.setToolTip('Move to the home page.')
        self.home_button.clicked.connect(self.loadHomePage)

        # signal catch from moving web pages.

        ##
        ## Download dialog
        ##
        self.window.urlChanged.connect(self.updateCurrentUrl)
        self.window.page().profile().downloadRequested.connect(
            self.on_download_requested)
        ##

        self.tab = QGridLayout()
        self.tab.setSpacing(0)
        self.tab.addWidget(self.reload_button, 1, 2)
        self.tab.addWidget(self.url_edit, 1, 3, 1, 10)
        self.tab.addWidget(self.window, 2, 0, 5, 16)
        self.tab.addWidget(self.progress, 7, 0, 1, 3)  #### Download
        self.setLayout(self.tab)

        #tab = QWidget()
        #tab.layout = QGridLayout(tab)
        #tab.layout.setSpacing(0)
        #tab.layout.addWidget(self.reload_button, 1, 2)
        #tab.layout.addWidget(self.url_edit, 1, 3, 1, 10)
        #tab.layout.addWidget(self.window,2, 0, 5, 16)
        #tab.layout.addWidget(self.progress, 7, 0, 1, 3) #### Download
        #tab.setLayout(tab.layout)
        #return tab

    def center(self):
        ''' centering widget
        '''
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def check_url_protocol(self, move_url):
        if (move_url[0:7] == 'http://' or move_url[0:8] == "https://"
                or move_url[0:8] == 'file:///' or move_url[0:6] == 'ftp://'):
            return True
        else:
            return False

    def check_url_protocol_ipv4(self, move_url):
        ''' return True if move_url is IPv4 using Regular expression
        '''
        return re.match(
            '(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])',
            move_url)

    def updateCurrentUrl(self):
        ''' rewriting url_edit when you move different web page.
        '''
        # current_url = self.window.url().toString()
        self.url_edit.clear()
        self.url_edit.insert(self.window.url().toString())

    def loadHomePage(self):
        ''' move to the home page
        '''
        #initurl = 'https://www.google.co.jp'
        #self.window.load(QUrl(initurl))
        self.window.load(QUrl(initurl))  ### Download

    def saveFile(self):
        print('download')

    @pyqtSlot(QWebEngineDownloadItem)
    def on_download_requested(self, download):
        # print('{} downloading to {}'.format(download.url(), download.path()))
        self.downloading_filename = QFileInfo(download.path()).fileName()
        self.progress.setValue(0)
        self.progress.show()
        download.downloadProgress.connect(self.on_download_progress)
        download.stateChanged.connect(self.on_download_state)
        download.accept()

    def on_download_progress(self, read, total):
        self.progress.setValue((total / read) * 100)
        self.progress.setFormat('{} : {}%'.format(self.downloading_filename,
                                                  (total / read) * 100))

    def on_download_state(self, state):
        if state == QWebEngineDownloadItem.DownloadRequested:
            print('requested')
        elif state == QWebEngineDownloadItem.DownloadInProgress:
            print('Download')
        elif state == QWebEngineDownloadItem.DownloadCompleted:
            #print('Download complete')
            sleep(1)  ################ Download
            self.progress.hide()
        elif state == QWebEngineDownloadItem.DownloadCancelled:
            print('cancel')
        elif state == QWebEngineDownloadItem.DownloadInterrupted:
            print('interrupt')
Ejemplo n.º 29
0
class _TimeViewer(object):
    """Class to interact with _Brain."""

    def __init__(self, brain, show_traces=False):
        from ..backends._pyvista import _require_minimum_version
        _require_minimum_version('0.24')

        # shared configuration
        self.brain = brain
        self.orientation = [
            'lateral',
            'medial',
            'rostral',
            'caudal',
            'dorsal',
            'ventral',
            'frontal',
            'parietal'
        ]
        self.default_smoothing_range = [0, 15]

        # detect notebook
        if brain._notebook:
            self.notebook = True
            self.configure_notebook()
            return
        else:
            self.notebook = False

        # Default configuration
        self.playback = False
        self.visibility = False
        self.refresh_rate_ms = max(int(round(1000. / 60.)), 1)
        self.default_scaling_range = [0.2, 2.0]
        self.default_playback_speed_range = [0.01, 1]
        self.default_playback_speed_value = 0.05
        self.default_status_bar_msg = "Press ? for help"
        self.act_data = {'lh': None, 'rh': None}
        self.color_cycle = None
        self.picked_points = {'lh': list(), 'rh': list()}
        self._mouse_no_mvt = -1
        self.icons = dict()
        self.actions = dict()
        self.keys = ('fmin', 'fmid', 'fmax')
        self.slider_length = 0.02
        self.slider_width = 0.04
        self.slider_color = (0.43137255, 0.44313725, 0.45882353)
        self.slider_tube_width = 0.04
        self.slider_tube_color = (0.69803922, 0.70196078, 0.70980392)

        # Direct access parameters:
        self.brain.time_viewer = self
        self.plotter = brain._renderer.plotter
        self.main_menu = self.plotter.main_menu
        self.window = self.plotter.app_window
        self.tool_bar = self.window.addToolBar("toolbar")
        self.status_bar = self.window.statusBar()
        self.interactor = self.plotter.interactor
        self.window.signal_close.connect(self.clean)

        # Derived parameters:
        self.playback_speed = self.default_playback_speed_value
        _check_option('show_traces', type(show_traces), [bool, str])
        if isinstance(show_traces, str) and show_traces == "separate":
            self.show_traces = True
            self.separate_canvas = True
        else:
            self.show_traces = show_traces
            self.separate_canvas = False

        self.load_icons()
        self.interactor_stretch = 3
        self.configure_time_label()
        self.configure_sliders()
        self.configure_scalar_bar()
        self.configure_playback()
        self.configure_point_picking()
        self.configure_menu()
        self.configure_tool_bar()
        self.configure_status_bar()

        # show everything at the end
        self.toggle_interface()
        with self.ensure_minimum_sizes():
            self.brain.show()

    @contextlib.contextmanager
    def ensure_minimum_sizes(self):
        sz = self.brain._size
        adjust_mpl = self.show_traces and not self.separate_canvas
        if not adjust_mpl:
            yield
        else:
            self.mpl_canvas.canvas.setMinimumSize(
                sz[0], int(round(sz[1] / self.interactor_stretch)))
            try:
                yield
            finally:
                self.mpl_canvas.canvas.setMinimumSize(0, 0)

    def toggle_interface(self, value=None):
        if value is None:
            self.visibility = not self.visibility
        else:
            self.visibility = value

        # update tool bar icon
        if self.visibility:
            self.actions["visibility"].setIcon(self.icons["visibility_on"])
        else:
            self.actions["visibility"].setIcon(self.icons["visibility_off"])

        # manage sliders
        for slider in self.plotter.slider_widgets:
            slider_rep = slider.GetRepresentation()
            if self.visibility:
                slider_rep.VisibilityOn()
            else:
                slider_rep.VisibilityOff()

        # manage time label
        time_label = self.brain._data['time_label']
        # if we actually have time points, we will show the slider so
        # hide the time actor
        have_ts = self.brain._times is not None and len(self.brain._times) > 1
        if self.time_actor is not None:
            if self.visibility and time_label is not None and not have_ts:
                self.time_actor.SetInput(time_label(self.brain._current_time))
                self.time_actor.VisibilityOn()
            else:
                self.time_actor.VisibilityOff()

        self.plotter.update()

    def _save_movie(self, filename, **kwargs):
        from PyQt5.QtCore import Qt
        from PyQt5.QtGui import QCursor

        def frame_callback(frame, n_frames):
            if frame == n_frames:
                # On the ImageIO step
                self.status_msg.setText(
                    "Saving with ImageIO: %s"
                    % filename
                )
                self.status_msg.show()
                self.status_progress.hide()
                self.status_bar.layout().update()
            else:
                self.status_msg.setText(
                    "Rendering images (frame %d / %d) ..."
                    % (frame + 1, n_frames)
                )
                self.status_msg.show()
                self.status_progress.show()
                self.status_progress.setRange(0, n_frames - 1)
                self.status_progress.setValue(frame)
                self.status_progress.update()
                self.status_progress.repaint()
            self.status_msg.update()
            self.status_msg.parent().update()
            self.status_msg.repaint()

        # temporarily hide interface
        default_visibility = self.visibility
        self.toggle_interface(value=False)
        # set cursor to busy
        default_cursor = self.interactor.cursor()
        self.interactor.setCursor(QCursor(Qt.WaitCursor))

        try:
            self.brain.save_movie(
                filename=filename,
                time_dilation=(1. / self.playback_speed),
                callback=frame_callback,
                **kwargs
            )
        except (Exception, KeyboardInterrupt):
            warn('Movie saving aborted:\n' + traceback.format_exc())

        # restore visibility
        self.toggle_interface(value=default_visibility)
        # restore cursor
        self.interactor.setCursor(default_cursor)

    @copy_doc(_Brain.save_movie)
    def save_movie(self, filename=None, **kwargs):
        from pyvista.plotting.qt_plotting import FileDialog

        if filename is None:
            self.status_msg.setText("Choose movie path ...")
            self.status_msg.show()
            self.status_progress.setValue(0)

            def _clean(unused):
                del unused
                self.status_msg.hide()
                self.status_progress.hide()

            dialog = FileDialog(
                self.plotter.app_window,
                callback=partial(self._save_movie, **kwargs)
            )
            dialog.setDirectory(os.getcwd())
            dialog.finished.connect(_clean)
            return dialog
        else:
            self._save_movie(filename=filename, **kwargs)
            return

    def apply_auto_scaling(self):
        self.brain.update_auto_scaling()
        for key in ('fmin', 'fmid', 'fmax'):
            self.reps[key].SetValue(self.brain._data[key])
        self.plotter.update()

    def restore_user_scaling(self):
        self.brain.update_auto_scaling(restore=True)
        for key in ('fmin', 'fmid', 'fmax'):
            self.reps[key].SetValue(self.brain._data[key])
        self.plotter.update()

    def toggle_playback(self, value=None):
        if value is None:
            self.playback = not self.playback
        else:
            self.playback = value

        # update tool bar icon
        if self.playback:
            self.actions["play"].setIcon(self.icons["pause"])
        else:
            self.actions["play"].setIcon(self.icons["play"])

        if self.playback:
            time_data = self.brain._data['time']
            max_time = np.max(time_data)
            if self.brain._current_time == max_time:  # start over
                self.brain.set_time_point(0)  # first index
            self._last_tick = time.time()

    def set_playback_speed(self, speed):
        self.playback_speed = speed

    @safe_event
    def play(self):
        if self.playback:
            try:
                self._advance()
            except Exception:
                self.toggle_playback(value=False)
                raise

    def _advance(self):
        this_time = time.time()
        delta = this_time - self._last_tick
        self._last_tick = time.time()
        time_data = self.brain._data['time']
        times = np.arange(self.brain._n_times)
        time_shift = delta * self.playback_speed
        max_time = np.max(time_data)
        time_point = min(self.brain._current_time + time_shift, max_time)
        # always use linear here -- this does not determine the data
        # interpolation mode, it just finds where we are (in time) in
        # terms of the time indices
        idx = np.interp(time_point, time_data, times)
        self.time_call(idx, update_widget=True)
        if time_point == max_time:
            self.toggle_playback(value=False)

    def set_slider_style(self, slider, show_label=True, show_cap=False):
        if slider is not None:
            slider_rep = slider.GetRepresentation()
            slider_rep.SetSliderLength(self.slider_length)
            slider_rep.SetSliderWidth(self.slider_width)
            slider_rep.SetTubeWidth(self.slider_tube_width)
            slider_rep.GetSliderProperty().SetColor(self.slider_color)
            slider_rep.GetTubeProperty().SetColor(self.slider_tube_color)
            slider_rep.GetLabelProperty().SetShadow(False)
            slider_rep.GetLabelProperty().SetBold(True)
            slider_rep.GetLabelProperty().SetColor(self.brain._fg_color)
            slider_rep.GetTitleProperty().ShallowCopy(
                slider_rep.GetLabelProperty()
            )
            if not show_cap:
                slider_rep.GetCapProperty().SetOpacity(0)
            if not show_label:
                slider_rep.ShowSliderLabelOff()

    def configure_notebook(self):
        from ._notebook import _NotebookInteractor
        self.brain._renderer.figure.display = _NotebookInteractor(self)

    def configure_time_label(self):
        self.time_actor = self.brain._data.get('time_actor')
        if self.time_actor is not None:
            self.time_actor.SetPosition(0.5, 0.03)
            self.time_actor.GetTextProperty().SetJustificationToCentered()
            self.time_actor.GetTextProperty().BoldOn()
            self.time_actor.VisibilityOff()

    def configure_scalar_bar(self):
        if self.brain._colorbar_added:
            scalar_bar = self.plotter.scalar_bar
            scalar_bar.SetOrientationToVertical()
            scalar_bar.SetHeight(0.6)
            scalar_bar.SetWidth(0.05)
            scalar_bar.SetPosition(0.02, 0.2)

    def configure_sliders(self):
        rng = _get_range(self.brain)
        # Orientation slider
        # default: put orientation slider on the first view
        if self.brain._hemi in ('split', 'both'):
            self.plotter.subplot(0, 0)

        # Use 'lh' as a reference for orientation for 'both'
        if self.brain._hemi == 'both':
            hemis_ref = ['lh']
        else:
            hemis_ref = self.brain._hemis
        for hemi in hemis_ref:
            if self.brain._hemi == 'split':
                ci = 0 if hemi == 'lh' else 1
            else:
                ci = 0
            for ri, view in enumerate(self.brain._views):
                self.plotter.subplot(ri, ci)
                self.orientation_call = ShowView(
                    plotter=self.plotter,
                    brain=self.brain,
                    orientation=self.orientation,
                    hemi=hemi,
                    row=ri,
                    col=ci,
                )
                orientation_slider = self.plotter.add_text_slider_widget(
                    self.orientation_call,
                    value=0,
                    data=self.orientation,
                    pointa=(0.82, 0.74),
                    pointb=(0.98, 0.74),
                    event_type='always'
                )
                self.orientation_call.slider_rep = \
                    orientation_slider.GetRepresentation()
                self.set_slider_style(orientation_slider, show_label=False)
                self.orientation_call(view, update_widget=True)

        # necessary because show_view modified subplot
        if self.brain._hemi in ('split', 'both'):
            self.plotter.subplot(0, 0)

        # Smoothing slider
        self.smoothing_call = IntSlider(
            plotter=self.plotter,
            callback=self.brain.set_data_smoothing,
            first_call=False,
        )
        smoothing_slider = self.plotter.add_slider_widget(
            self.smoothing_call,
            value=self.brain._data['smoothing_steps'],
            rng=self.default_smoothing_range, title="smoothing",
            pointa=(0.82, 0.90),
            pointb=(0.98, 0.90)
        )
        self.smoothing_call.slider_rep = smoothing_slider.GetRepresentation()

        # Time slider
        max_time = len(self.brain._data['time']) - 1
        # VTK on macOS bombs if we create these then hide them, so don't
        # even create them
        if max_time < 1:
            self.time_call = None
            time_slider = None
        else:
            self.time_call = TimeSlider(
                plotter=self.plotter,
                brain=self.brain,
                first_call=False,
                callback=self.plot_time_line,
            )
            time_slider = self.plotter.add_slider_widget(
                self.time_call,
                value=self.brain._data['time_idx'],
                rng=[0, max_time],
                pointa=(0.23, 0.1),
                pointb=(0.77, 0.1),
                event_type='always'
            )
            self.time_call.slider_rep = time_slider.GetRepresentation()
            # configure properties of the time slider
            time_slider.GetRepresentation().SetLabelFormat('idx=%0.1f')

        current_time = self.brain._current_time
        assert current_time is not None  # should never be the case, float
        time_label = self.brain._data['time_label']
        if callable(time_label):
            current_time = time_label(current_time)
        else:
            current_time = time_label
        if time_slider is not None:
            time_slider.GetRepresentation().SetTitleText(current_time)
        if self.time_actor is not None:
            self.time_actor.SetInput(current_time)
        del current_time

        # Playback speed slider
        if time_slider is None:
            self.playback_speed_call = None
            playback_speed_slider = None
        else:
            self.playback_speed_call = SmartSlider(
                plotter=self.plotter,
                callback=self.set_playback_speed,
            )
            playback_speed_slider = self.plotter.add_slider_widget(
                self.playback_speed_call,
                value=self.default_playback_speed_value,
                rng=self.default_playback_speed_range, title="speed",
                pointa=(0.02, 0.1),
                pointb=(0.18, 0.1),
                event_type='always'
            )
            self.playback_speed_call.slider_rep = \
                playback_speed_slider.GetRepresentation()

        # Colormap slider
        pointa = np.array((0.82, 0.26))
        pointb = np.array((0.98, 0.26))
        shift = np.array([0, 0.1])
        # fmin
        self.fmin_call = BumpColorbarPoints(
            plotter=self.plotter,
            brain=self.brain,
            name="fmin"
        )
        fmin_slider = self.plotter.add_slider_widget(
            self.fmin_call,
            value=self.brain._data["fmin"],
            rng=rng, title="clim",
            pointa=pointa,
            pointb=pointb,
            event_type="always",
        )
        # fmid
        self.fmid_call = BumpColorbarPoints(
            plotter=self.plotter,
            brain=self.brain,
            name="fmid",
        )
        fmid_slider = self.plotter.add_slider_widget(
            self.fmid_call,
            value=self.brain._data["fmid"],
            rng=rng, title="",
            pointa=pointa + shift,
            pointb=pointb + shift,
            event_type="always",
        )
        # fmax
        self.fmax_call = BumpColorbarPoints(
            plotter=self.plotter,
            brain=self.brain,
            name="fmax",
        )
        fmax_slider = self.plotter.add_slider_widget(
            self.fmax_call,
            value=self.brain._data["fmax"],
            rng=rng, title="",
            pointa=pointa + 2 * shift,
            pointb=pointb + 2 * shift,
            event_type="always",
        )
        # fscale
        self.fscale_call = UpdateColorbarScale(
            plotter=self.plotter,
            brain=self.brain,
        )
        fscale_slider = self.plotter.add_slider_widget(
            self.fscale_call,
            value=1.0,
            rng=self.default_scaling_range, title="fscale",
            pointa=(0.82, 0.10),
            pointb=(0.98, 0.10)
        )
        self.fscale_call.fscale_slider_rep = fscale_slider.GetRepresentation()

        # register colorbar slider representations
        self.reps = {
            "fmin": fmin_slider.GetRepresentation(),
            "fmid": fmid_slider.GetRepresentation(),
            "fmax": fmax_slider.GetRepresentation(),
        }
        self.fmin_call.reps = self.reps
        self.fmid_call.reps = self.reps
        self.fmax_call.reps = self.reps
        self.fscale_call.reps = self.reps

        # set the slider style
        self.set_slider_style(smoothing_slider)
        self.set_slider_style(fmin_slider)
        self.set_slider_style(fmid_slider)
        self.set_slider_style(fmax_slider)
        self.set_slider_style(fscale_slider)
        if time_slider is not None:
            self.set_slider_style(playback_speed_slider)
            self.set_slider_style(time_slider)

        # store sliders for linking
        self._time_slider = time_slider
        self._playback_speed_slider = playback_speed_slider

    def configure_playback(self):
        self.plotter.add_callback(self.play, self.refresh_rate_ms)

    def configure_point_picking(self):
        from ..backends._pyvista import _update_picking_callback
        if self.show_traces:
            # use a matplotlib canvas
            self.color_cycle = _ReuseCycle(_get_color_list())
            win = self.plotter.app_window
            dpi = win.windowHandle().screen().logicalDotsPerInch()
            w, h = win.geometry().width() / dpi, win.geometry().height() / dpi
            h /= 3  # one third of the window
            self.mpl_canvas = MplCanvas(self, w, h, dpi)
            xlim = [np.min(self.brain._data['time']),
                    np.max(self.brain._data['time'])]
            with warnings.catch_warnings():
                warnings.filterwarnings("ignore", category=UserWarning)
                self.mpl_canvas.axes.set(xlim=xlim)
            vlayout = self.plotter.frame.layout()
            if not self.separate_canvas:
                vlayout.addWidget(self.mpl_canvas.canvas)
                vlayout.setStretch(0, self.interactor_stretch)
                vlayout.setStretch(1, 1)
            self.mpl_canvas.set_color(
                bg_color=self.brain._bg_color,
                fg_color=self.brain._fg_color,
            )
            self.mpl_canvas.show()

            # get brain data
            for idx, hemi in enumerate(['lh', 'rh']):
                hemi_data = self.brain._data.get(hemi)
                if hemi_data is not None:
                    act_data = hemi_data['array']
                    if act_data.ndim == 3:
                        act_data = np.linalg.norm(act_data, axis=1)
                    smooth_mat = hemi_data['smooth_mat']
                    if smooth_mat is not None:
                        act_data = smooth_mat.dot(act_data)
                    self.act_data[hemi] = act_data

                    # simulate a picked renderer
                    if self.brain._hemi == 'split':
                        self.picked_renderer = self.plotter.renderers[idx]
                    else:
                        self.picked_renderer = self.plotter.renderers[0]

                    # initialize the default point
                    color = next(self.color_cycle)
                    ind = np.unravel_index(
                        np.argmax(self.act_data[hemi], axis=None),
                        self.act_data[hemi].shape
                    )
                    vertex_id = ind[0]
                    mesh = hemi_data['mesh'][-1]
                    line = self.plot_time_course(hemi, vertex_id, color)
                    self.add_point(hemi, mesh, vertex_id, line, color)

            self.plot_time_line()

            _update_picking_callback(
                self.plotter,
                self.on_mouse_move,
                self.on_button_press,
                self.on_button_release,
                self.on_pick
            )

    def load_icons(self):
        from PyQt5.QtGui import QIcon
        _init_resources()
        self.icons["help"] = QIcon(":/help.svg")
        self.icons["play"] = QIcon(":/play.svg")
        self.icons["pause"] = QIcon(":/pause.svg")
        self.icons["scale"] = QIcon(":/scale.svg")
        self.icons["clear"] = QIcon(":/clear.svg")
        self.icons["movie"] = QIcon(":/movie.svg")
        self.icons["restore"] = QIcon(":/restore.svg")
        self.icons["screenshot"] = QIcon(":/screenshot.svg")
        self.icons["visibility_on"] = QIcon(":/visibility_on.svg")
        self.icons["visibility_off"] = QIcon(":/visibility_off.svg")

    def configure_tool_bar(self):
        self.actions["screenshot"] = self.tool_bar.addAction(
            self.icons["screenshot"],
            "Take a screenshot",
            self.plotter._qt_screenshot
        )
        self.actions["movie"] = self.tool_bar.addAction(
            self.icons["movie"],
            "Save movie...",
            self.save_movie
        )
        self.actions["visibility"] = self.tool_bar.addAction(
            self.icons["visibility_on"],
            "Toggle Visibility",
            self.toggle_interface
        )
        self.actions["play"] = self.tool_bar.addAction(
            self.icons["play"],
            "Play/Pause",
            self.toggle_playback
        )
        self.actions["scale"] = self.tool_bar.addAction(
            self.icons["scale"],
            "Auto-Scale",
            self.apply_auto_scaling
        )
        self.actions["restore"] = self.tool_bar.addAction(
            self.icons["restore"],
            "Restore scaling",
            self.restore_user_scaling
        )
        self.actions["clear"] = self.tool_bar.addAction(
            self.icons["clear"],
            "Clear traces",
            self.clear_points
        )
        self.actions["help"] = self.tool_bar.addAction(
            self.icons["help"],
            "Help",
            self.help
        )

        self.actions["movie"].setShortcut("ctrl+shift+s")
        self.actions["visibility"].setShortcut("i")
        self.actions["play"].setShortcut(" ")
        self.actions["scale"].setShortcut("s")
        self.actions["restore"].setShortcut("r")
        self.actions["clear"].setShortcut("c")
        self.actions["help"].setShortcut("?")

    def configure_menu(self):
        # remove default picking menu
        to_remove = list()
        for action in self.main_menu.actions():
            if action.text() == "Tools":
                to_remove.append(action)
        for action in to_remove:
            self.main_menu.removeAction(action)

        # add help menu
        menu = self.main_menu.addMenu('Help')
        menu.addAction('Show MNE key bindings\t?', self.help)

    def configure_status_bar(self):
        from PyQt5.QtWidgets import QLabel, QProgressBar
        self.status_msg = QLabel(self.default_status_bar_msg)
        self.status_progress = QProgressBar()
        self.status_bar.layout().addWidget(self.status_msg, 1)
        self.status_bar.layout().addWidget(self.status_progress, 0)
        self.status_progress.hide()

    def on_mouse_move(self, vtk_picker, event):
        if self._mouse_no_mvt:
            self._mouse_no_mvt -= 1

    def on_button_press(self, vtk_picker, event):
        self._mouse_no_mvt = 2

    def on_button_release(self, vtk_picker, event):
        if self._mouse_no_mvt > 0:
            x, y = vtk_picker.GetEventPosition()
            # programmatically detect the picked renderer
            self.picked_renderer = self.plotter.iren.FindPokedRenderer(x, y)
            # trigger the pick
            self.plotter.picker.Pick(x, y, 0, self.picked_renderer)
        self._mouse_no_mvt = 0

    def on_pick(self, vtk_picker, event):
        cell_id = vtk_picker.GetCellId()
        mesh = vtk_picker.GetDataSet()

        if mesh is None or cell_id == -1:
            return

        if hasattr(mesh, "_is_point"):
            self.remove_point(mesh)
        elif self._mouse_no_mvt:
            hemi = mesh._hemi
            pos = vtk_picker.GetPickPosition()
            vtk_cell = mesh.GetCell(cell_id)
            cell = [vtk_cell.GetPointId(point_id) for point_id
                    in range(vtk_cell.GetNumberOfPoints())]
            vertices = mesh.points[cell]
            idx = np.argmin(abs(vertices - pos), axis=0)
            vertex_id = cell[idx[0]]

            if vertex_id not in self.picked_points[hemi]:
                color = next(self.color_cycle)

                # update associated time course
                line = self.plot_time_course(hemi, vertex_id, color)

                # add glyph at picked point
                self.add_point(hemi, mesh, vertex_id, line, color)

    def add_point(self, hemi, mesh, vertex_id, line, color):
        from ..backends._pyvista import _sphere
        center = mesh.GetPoints().GetPoint(vertex_id)

        # from the picked renderer to the subplot coords
        rindex = self.plotter.renderers.index(self.picked_renderer)
        row, col = self.plotter.index_to_loc(rindex)

        actors = list()
        spheres = list()
        for ri, view in enumerate(self.brain._views):
            self.plotter.subplot(ri, col)
            # Using _sphere() instead of renderer.sphere() for 2 reasons:
            # 1) renderer.sphere() fails on Windows in a scenario where a lot
            #    of picking requests are done in a short span of time (could be
            #    mitigated with synchronization/delay?)
            # 2) the glyph filter is used in renderer.sphere() but only one
            #    sphere is required in this function.
            actor, sphere = _sphere(
                plotter=self.plotter,
                center=np.array(center),
                color=color,
                radius=4.0,
            )
            actors.append(actor)
            spheres.append(sphere)

        # add metadata for picking
        for sphere in spheres:
            sphere._is_point = True
            sphere._hemi = hemi
            sphere._line = line
            sphere._actors = actors
            sphere._color = color
            sphere._vertex_id = vertex_id

        self.picked_points[hemi].append(vertex_id)

        # this is used for testing only
        if hasattr(self, "_spheres"):
            self._spheres += spheres
        else:
            self._spheres = spheres

    def remove_point(self, mesh):
        mesh._line.remove()
        self.mpl_canvas.update_plot()
        self.picked_points[mesh._hemi].remove(mesh._vertex_id)
        with warnings.catch_warnings(record=True):
            # We intentionally ignore these in case we have traversed the
            # entire color cycle
            warnings.simplefilter('ignore')
            self.color_cycle.restore(mesh._color)
        self.plotter.remove_actor(mesh._actors)
        mesh._actors = None

    def clear_points(self):
        if hasattr(self, "_spheres"):
            for sphere in self._spheres:
                vertex_id = sphere._vertex_id
                hemi = sphere._hemi
                if vertex_id in self.picked_points[hemi]:
                    self.remove_point(sphere)
            self._spheres.clear()

    def plot_time_course(self, hemi, vertex_id, color):
        if not hasattr(self, "mpl_canvas"):
            return
        time = self.brain._data['time']
        hemi_str = 'L' if hemi == 'lh' else 'R'
        hemi_int = 0 if hemi == 'lh' else 1
        mni = vertex_to_mni(
            vertices=vertex_id,
            hemis=hemi_int,
            subject=self.brain._subject_id,
            subjects_dir=self.brain._subjects_dir
        )
        label = "{}:{} MNI: {}".format(
            hemi_str, str(vertex_id).ljust(6),
            ', '.join('%5.1f' % m for m in mni))
        line = self.mpl_canvas.plot(
            time,
            self.act_data[hemi][vertex_id, :],
            label=label,
            lw=1.,
            color=color
        )
        return line

    def plot_time_line(self):
        if not hasattr(self, "mpl_canvas"):
            return
        if isinstance(self.show_traces, bool) and self.show_traces:
            # add time information
            current_time = self.brain._current_time
            if not hasattr(self, "time_line"):
                self.time_line = self.mpl_canvas.plot_time_line(
                    x=current_time,
                    label='time',
                    color=self.brain._fg_color,
                    lw=1,
                )
            else:
                self.time_line.set_xdata(current_time)
                self.mpl_canvas.update_plot()

    def help(self):
        pairs = [
            ('?', 'Display help window'),
            ('i', 'Toggle interface'),
            ('s', 'Apply auto-scaling'),
            ('r', 'Restore original clim'),
            ('c', 'Clear all traces'),
            ('Space', 'Start/Pause playback'),
        ]
        text1, text2 = zip(*pairs)
        text1 = '\n'.join(text1)
        text2 = '\n'.join(text2)
        _show_help(
            col1=text1,
            col2=text2,
            width=5,
            height=2,
        )

    @safe_event
    def clean(self):
        # resolve the reference cycle
        self.clear_points()
        self.actions.clear()
        self.reps = None
        self._time_slider = None
        self._playback_speed_slider = None
        self.orientation_call.plotter = None
        self.orientation_call.brain = None
        self.orientation_call = None
        self.smoothing_call.plotter = None
        self.smoothing_call = None
        if self.time_call is not None:
            self.time_call.plotter = None
            self.time_call.brain = None
            self.time_call = None
            self.playback_speed_call.plotter = None
            self.playback_speed_call = None
        self.fmin_call.plotter = None
        self.fmin_call.brain = None
        self.fmin_call = None
        self.fmid_call.plotter = None
        self.fmid_call.brain = None
        self.fmid_call = None
        self.fmax_call.plotter = None
        self.fmax_call.brain = None
        self.fmax_call = None
        self.fscale_call.plotter = None
        self.fscale_call.brain = None
        self.fscale_call = None
        self.brain.time_viewer = None
        self.brain = None
        self.plotter = None
        self.main_menu = None
        self.window = None
        self.tool_bar = None
        self.status_bar = None
        self.interactor = None
        if hasattr(self, "mpl_canvas"):
            self.mpl_canvas.close()
            self.mpl_canvas.time_viewer = None
            self.mpl_canvas.canvas = None
            self.mpl_canvas = None
        self.time_actor = None
        self.picked_renderer = None
        self.act_data["lh"] = None
        self.act_data["rh"] = None
        self.act_data = None
Ejemplo n.º 30
0
class Ui_MainWindow(QMainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()
        self.setWindowIcon(QIcon('icon.ico'))
        self.setFixedSize(481, 447)

    def setupUi(self):
        self.centralwidget = QWidget(self)
        self.label_info = QLabel(self.centralwidget)
        self.label_info.setGeometry(QRect(20, 20, 415, 20))
        self.verticalLayoutWidget = QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QRect(20, 50, 121, 271))
        self.verticalLayout = QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.checkBox = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox)
        self.checkBox_2 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_2)
        self.checkBox_3 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_3)
        self.checkBox_4 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_4)
        self.checkBox_5 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_5)
        self.checkBox_6 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_6)
        self.checkBox_7 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_7)
        self.checkBox_8 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_8)
        self.checkBox_9 = QCheckBox(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.checkBox_9)
        self.verticalLayoutWidget_2 = QWidget(self.centralwidget)
        self.verticalLayoutWidget_2.setGeometry(QRect(170, 50, 131, 271))
        self.verticalLayout_2 = QVBoxLayout(self.verticalLayoutWidget_2)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.checkBox_10 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_10)
        self.checkBox_11 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_11)
        self.checkBox_12 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_12)
        self.checkBox_13 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_13)
        self.checkBox_14 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_14)
        self.checkBox_15 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_15)
        self.checkBox_16 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_16)
        self.checkBox_17 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_17)
        self.checkBox_18 = QCheckBox(self.verticalLayoutWidget_2)
        self.verticalLayout_2.addWidget(self.checkBox_18)
        self.verticalLayoutWidget_3 = QWidget(self.centralwidget)
        self.verticalLayoutWidget_3.setGeometry(QRect(330, 50, 131, 271))
        self.verticalLayout_3 = QVBoxLayout(self.verticalLayoutWidget_3)
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.checkBox_19 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_19)
        self.checkBox_20 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_20)
        self.checkBox_21 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_21)
        self.checkBox_22 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_22)
        self.checkBox_23 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_23)
        self.checkBox_24 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_24)
        self.checkBox_25 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_25)
        self.checkBox_26 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_26)
        self.checkBox_27 = QCheckBox(self.verticalLayoutWidget_3)
        self.verticalLayout_3.addWidget(self.checkBox_27)
        self.label_note = QLabel(self.centralwidget)
        self.label_note.setGeometry(QRect(20, 330, 350, 16))
        self.label_space = QLabel(self.centralwidget)
        self.label_space.setGeometry(QRect(20, 350, 350, 16))
        self.label_size = QLabel(self.centralwidget)
        self.label_size.setGeometry(QRect(200, 350, 350, 16))
        self.horizontalLayoutWidget = QWidget(self.centralwidget)
        self.horizontalLayoutWidget.setGeometry(QRect(379, 380, 81, 31))
        self.horizontalLayout = QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.button_uninstall = QPushButton(self.horizontalLayoutWidget)
        self.horizontalLayout.addWidget(self.button_uninstall)
        self.progressbar = QProgressBar(self.centralwidget)
        self.progressbar.setGeometry(QRect(20, 40, 175, 10))
        self.progressbar.hide()
        self.horizontalLayoutWidget_2 = QWidget(self.centralwidget)
        self.horizontalLayoutWidget_2.setGeometry(QRect(20, 380, 160, 31))
        self.horizontalLayout_2 = QHBoxLayout(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.button_select_all = QPushButton(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.addWidget(self.button_select_all)
        self.button_deselect_all = QPushButton(self.horizontalLayoutWidget_2)
        self.horizontalLayout_2.addWidget(self.button_deselect_all)
        self.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 481, 21))
        self.menuHelp = QMenu(self.menubar)
        self.setMenuBar(self.menubar)
        self.actionRefresh = QAction(self)
        self.actionHomepage = QAction(self)
        self.actionAbout = QAction(self)
        self.actionQuit = QAction(self)
        self.menuHelp.addAction(self.actionRefresh)
        self.menuHelp.addAction(self.actionHomepage)
        self.menuHelp.addAction(self.actionAbout)
        self.menuHelp.addSeparator()
        self.menuHelp.addAction(self.actionQuit)
        self.menubar.addAction(self.menuHelp.menuAction())

        self.retranslateUi()
        QMetaObject.connectSlotsByName(self)

    def retranslateUi(self):
        _translate = QCoreApplication.translate

        self.setWindowTitle(_translate("MainWindow", "PyDebloatX"))

        self.menuHelp.setTitle(_translate("MainWindow", "&Help"))
        self.actionRefresh.setText(_translate("MainWindow", "&Refresh"))
        self.actionRefresh.setShortcut(_translate("MainWindow", "Ctrl+R"))
        self.actionHomepage.setText(_translate("MainWindow", "&Github"))
        self.actionHomepage.setShortcut(_translate("MainWindow", "Ctrl+G"))
        self.actionAbout.setText(_translate("MainWindow", "&About"))
        self.actionAbout.setShortcut(_translate("MainWindow", "Ctrl+A"))
        self.actionQuit.setText(_translate("MainWindow", "&Quit"))
        self.actionQuit.setShortcut(_translate("MainWindow", "Ctrl+Q"))

        self.label_info.setText(_translate("MainWindow", "Updating list of installed apps..."))

        self.checkBox.setText(_translate("MainWindow", "3D Builder"))
        self.checkBox_2.setText(_translate("MainWindow", "3D Viewer"))
        self.checkBox_3.setText(_translate("MainWindow", "Alarms and Clock"))
        self.checkBox_4.setText(_translate("MainWindow", "Calculator"))
        self.checkBox_5.setText(_translate("MainWindow", "Calendar and Mail"))
        self.checkBox_6.setText(_translate("MainWindow", "Camera"))
        self.checkBox_7.setText(_translate("MainWindow", "Get Help"))
        self.checkBox_8.setText(_translate("MainWindow", "Groove Music"))
        self.checkBox_9.setText(_translate("MainWindow", "Maps"))

        self.checkBox_10.setText(_translate("MainWindow", "Messaging"))
        self.checkBox_11.setText(_translate("MainWindow", "Money"))
        self.checkBox_12.setText(_translate("MainWindow", "Movies && TV"))
        self.checkBox_13.setText(_translate("MainWindow", "News"))
        self.checkBox_14.setText(_translate("MainWindow", "Office"))
        self.checkBox_15.setText(_translate("MainWindow", "OneNote"))
        self.checkBox_16.setText(_translate("MainWindow", "Paint 3D"))
        self.checkBox_17.setText(_translate("MainWindow", "People"))
        self.checkBox_18.setText(_translate("MainWindow", "Photos"))

        self.checkBox_19.setText(_translate("MainWindow", "Skype"))
        self.checkBox_20.setText(_translate("MainWindow", "Solitaire"))
        self.checkBox_21.setText(_translate("MainWindow", "Sports"))
        self.checkBox_22.setText(_translate("MainWindow", "Tips"))
        self.checkBox_23.setText(_translate("MainWindow", "Voice Recorder"))
        self.checkBox_24.setText(_translate("MainWindow", "Weather"))
        self.checkBox_25.setText(_translate("MainWindow", "Windows Feedback"))
        self.checkBox_26.setText(_translate("MainWindow", "Xbox"))
        self.checkBox_27.setText(_translate("MainWindow", "Your Phone"))

        self.label_note.setText(_translate("MainWindow", "NOTE: Microsoft Edge and Cortana cannot be uninstalled using this GUI."))
        self.label_space.setText(_translate("MainWindow", "Total amount of disk space you gain:"))
        self.label_size.setText(_translate("MainWindow", "0 MB"))

        self.button_select_all.setText(_translate("MainWindow", "Select All"))
        self.button_deselect_all.setText(_translate("MainWindow", "Deselect All"))

        self.button_uninstall.setText(_translate("MainWindow", "Uninstall"))

        self.checkBox.setToolTip('View, create, and personalize 3D objects.')
        self.checkBox_2.setToolTip('View 3D models and animations in real-time.')
        self.checkBox_3.setToolTip('A combination of alarm clock, world clock, timer, and stopwatch.')
        self.checkBox_4.setToolTip('A calculator that includes standard, scientific, and programmer modes, as well as a unit converter.')
        self.checkBox_5.setToolTip('Stay up to date with email and schedule managing.')
        self.checkBox_6.setToolTip('Point and shoot to take pictures on Windows 10.')
        self.checkBox_7.setToolTip('Provide a way to ask a question and get recommended solutions or contact assisted support.')
        self.checkBox_8.setToolTip('Listen to music on Windows, iOS, and Android devices.')
        self.checkBox_9.setToolTip('Search for places to get directions, business info, and reviews.')

        self.checkBox_10.setToolTip('Quick, reliable SMS, MMS and RCS messaging from your phone.')
        self.checkBox_11.setToolTip('Finance calculators, currency exchange rates and commodity prices from around the world.')
        self.checkBox_12.setToolTip('All your movies and TV shows, all in one place, on all your devices.')
        self.checkBox_13.setToolTip('Deliver breaking news and trusted, in-depth reporting from the world\'s best journalists.')
        self.checkBox_14.setToolTip('Find all your Office apps and files in one place.')
        self.checkBox_15.setToolTip('Digital notebook for capturing and organizing everything across your devices.')
        self.checkBox_16.setToolTip('Make 2D masterpieces or 3D models that you can play with from all angles.')
        self.checkBox_17.setToolTip('Connect with all your friends, family, colleagues, and acquaintances in one place.')
        self.checkBox_18.setToolTip('View and edit your photos and videos, make movies, and create albums.')

        self.checkBox_19.setToolTip('Instant message, voice or video call application.')
        self.checkBox_20.setToolTip('Solitaire is one of the most played computer card games of all time.')
        self.checkBox_21.setToolTip('Live scores and in-depth game experiences for more than 150 leagues.')
        self.checkBox_22.setToolTip('Provide users with information and tips about operating system features.')
        self.checkBox_23.setToolTip('Record sounds, lectures, interviews, and other events.')
        self.checkBox_24.setToolTip('Latest weather conditions, accurate 10-day and hourly forecasts.')
        self.checkBox_25.setToolTip('Provide feedback about Windows and apps by sharing suggestions or problems.')
        self.checkBox_26.setToolTip('Browse the catalogue, view recommendations, and discover PC games with Xbox Game Pass.')
        self.checkBox_27.setToolTip('Link your Android phone and PC to view and reply to text messages, access mobile apps, and receive notifications.')
Ejemplo n.º 31
0
class MainWindow(QtWidgets.QMainWindow):
    MaxRecentFiles = 5

    def __init__(self, app_title="CSV Viewer"):
        super().__init__()
        self.progress = QProgressBar()
        self.threadpool = QThreadPool()
        self.app_title = app_title
        self.setMinimumSize(600, 300)
        self.df = None
        self.round_num = 2
        self.recentFileActs = []

        # settings
        self.settings = QtCore.QSettings('CSV_Viewer', 'CSV_Viewer')
        self.round_num = self.settings.value('round_numbers', self.round_num, int)

        # toolbar
        self.toolbar = QToolBar("MainToolbar")
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.addToolBar(self.toolbar)

        # open action
        style = self.toolbar.style()
        icon = style.standardIcon(QStyle.SP_FileDialogStart)
        self.button_open = QAction(icon, "Open", self)
        self.button_open.setShortcut('Ctrl+O')
        self.button_open.setStatusTip("Open CSV file...")
        self.button_open.triggered.connect(self.onToolbarOpenButtonClick)
        self.toolbar.addAction(self.button_open)
        self.button_open.setEnabled(True)

        # summary action
        style_summary = self.toolbar.style()
        icon = style_summary.standardIcon(QStyle.SP_FileDialogListView)
        self.button_summary = QAction(icon, "Summary", self)
        self.button_summary.setShortcut('Ctrl+S')
        self.button_summary.setStatusTip("Show summary for the current file")
        self.button_summary.triggered.connect(self.onToolbarSummaryButtonClick)
        self.toolbar.addAction(self.button_summary)

        # info action
        style_info = self.toolbar.style()
        icon = style_info.standardIcon(QStyle.SP_FileIcon)
        self.button_info = QAction(icon, "Info", self)
        self.button_info.setShortcut('Ctrl+I')
        self.button_info.setStatusTip("Show summary for the current file")
        self.button_info.triggered.connect(self.onToolbarInfoButtonClick)
        self.toolbar.addAction(self.button_info)

        # resize action
        style_resize = self.toolbar.style()
        icon = style_resize.standardIcon(QStyle.SP_BrowserReload)
        self.button_resize = QAction(icon, "Resize columns", self)
        self.button_resize.setShortcut('Ctrl+R')
        self.button_resize.setStatusTip("Resize columns width to content")
        self.button_resize.triggered.connect(self.onResizeColumns)
        self.toolbar.addAction(self.button_resize)

        # export to xlsx action
        style_xlsx = self.toolbar.style()
        icon = style_xlsx.standardIcon(QStyle.SP_FileLinkIcon)
        self.button_xlsx = QAction(icon, "Xlsx", self)
        self.button_xlsx.setStatusTip("Export data to xlsx file")
        self.button_xlsx.triggered.connect(self.onExportXlsx)
        self.toolbar.addAction(self.button_xlsx)

        # export to sqlite action
        style_sqlite = self.toolbar.style()
        icon = style_sqlite.standardIcon(QStyle.SP_FileLinkIcon)
        self.button_sqlite = QAction(icon, "SQLite", self)
        self.button_sqlite.setStatusTip("Export data to SQLite database")
        self.button_sqlite.triggered.connect(self.onExportSQLite)
        self.toolbar.addAction(self.button_sqlite)

        # export to html action
        style_html = self.toolbar.style()
        icon = style_html.standardIcon(QStyle.SP_FileLinkIcon)
        self.button_html = QAction(icon, "HTML", self)
        self.button_html.setStatusTip("Export data to HTML file")
        self.button_html.triggered.connect(self.onExportHTML)
        self.toolbar.addAction(self.button_html)

        # export to CSV action
        style_csv = self.toolbar.style()
        icon = style_csv.standardIcon(QStyle.SP_FileLinkIcon)
        self.button_csv = QAction(icon, "CSV", self)
        self.button_csv.setStatusTip("Export data to CSV file")
        self.button_csv.triggered.connect(self.onExportCSV)
        self.toolbar.addAction(self.button_csv)

        # export to Markdown action
        style_mark = self.toolbar.style()
        icon = style_mark.standardIcon(QStyle.SP_FileLinkIcon)
        self.button_mark = QAction(icon, "Markdown", self)
        self.button_mark.setStatusTip("Export data to Markdown file")
        self.button_mark.triggered.connect(self.onExportMarkdown)
        self.toolbar.addAction(self.button_mark)

        # import data from world bank climate api
        style_api = self.toolbar.style()
        icon = style_api.standardIcon(QStyle.SP_DialogSaveButton)
        self.button_api = QAction(icon, "API", self)
        self.button_api.setStatusTip("Import data from World Bank Climate API")
        self.button_api.triggered.connect(self.onImportFromAPI)
        self.toolbar.addAction(self.button_api)
        self.button_api.setEnabled(True)

        # close action
        style_close = self.toolbar.style()
        icon = style_close.standardIcon(QStyle.SP_DialogCloseButton)
        self.button_close = QAction(icon, "Close", self)
        self.button_close.setShortcut('Ctrl+X')
        self.button_close.setStatusTip("Close CSV file...")
        self.button_close.triggered.connect(self.onToolbarCloseButtonClick)
        self.toolbar.addAction(self.button_close)

        # quit action
        self.button_quit = QAction("Quit", self)
        self.button_quit.setShortcut('Ctrl+Q')
        self.button_quit.setStatusTip("Quit application")
        self.button_quit.triggered.connect(self.close)

        # toolbar show/hide action
        self.button_tool = QAction("Show/Hide toolbar", self)
        self.button_tool.setShortcut('Ctrl+T')
        self.button_tool.setStatusTip("Show or hide toolbar")
        self.button_tool.triggered.connect(self.showToolbar)

        # remove NaN
        self.button_nan = QAction("Remove NaN", self)
        self.button_nan.setShortcut('Ctrl+R')
        self.button_nan.setStatusTip("Remove rows with missing values")
        self.button_nan.triggered.connect(self.onRemoveNaN)

        # settings action
        style_settings = self.toolbar.style()
        icon = style_settings.standardIcon(QStyle.SP_ComputerIcon)
        self.button_settings = QAction(icon, "Settings", self)
        self.button_settings.setStatusTip("Application settings")
        self.button_settings.triggered.connect(self.onSettings)
        self.toolbar.addAction(self.button_settings)
        self.button_settings.setEnabled(True)

        # about action
        style_about = self.toolbar.style()
        icon = style_about.standardIcon(QStyle.SP_FileDialogInfoView)
        self.button_about = QAction(icon, "About", self)
        self.button_about.setStatusTip("About application")
        self.button_about.triggered.connect(self.about)
        self.toolbar.addAction(self.button_about)
        self.button_about.setEnabled(True)

        self.setButtons(False)

        # recent menu action
        for i in range(MainWindow.MaxRecentFiles):
            self.recentFileActs.append(
                QAction(self, visible=False, triggered=self.openRecentFile)
            )

        # menu bar
        menu = self.menuBar()
        file_menu = menu.addMenu("&File")
        file_menu.addAction(self.button_open)
        file_menu.addAction(self.button_close)
        file_menu.addSeparator()
        file_menu.addAction(self.button_nan)
        file_menu.addSeparator()
        file_menu.addAction(self.button_settings)
        self.separatorAct = file_menu.addSeparator()

        for i in range(MainWindow.MaxRecentFiles):
            file_menu.addAction(self.recentFileActs[i])
        file_menu.addSeparator()

        file_menu.addAction(self.button_quit)

        view_menu = menu.addMenu("Vie&w")
        view_menu.addAction(self.button_summary)
        view_menu.addAction(self.button_info)
        view_menu.addSeparator()
        view_menu.addAction(self.button_resize)
        view_menu.addSeparator()
        view_menu.addAction(self.button_tool)

        export_menu = menu.addMenu("&Export")
        export_menu.addAction(self.button_xlsx)
        export_menu.addAction(self.button_sqlite)
        export_menu.addAction(self.button_html)
        export_menu.addAction(self.button_csv)
        export_menu.addAction(self.button_mark)

        import_menu = menu.addMenu("&Import")
        import_menu.addAction(self.button_api)

        help_menu = menu.addMenu("&Help")
        help_menu.addAction(self.button_about)

        self.updateRecentFileActions()

        # status bar
        self.my_status = QStatusBar(self)
        self.my_status.addPermanentWidget(self.progress)
        self.progress.hide()
        self.labelStatus = QLabel("Rows: 0 Cols: 0")
        self.my_status.addPermanentWidget(self.labelStatus)
        self.setStatusBar(self.my_status)

        # set TableView
        self.table = QtWidgets.QTableView()
        self.table.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
        self.table.setSelectionMode(QtWidgets.QTableView.SingleSelection)

        self.setCentralWidget(self.table)
        self.setWindowTitle(self.app_title)
        self.setMinimumSize(400, 250)
        self.setGeometry(200, 100, 1000, 600)

    def onToolbarOpenButtonClick(self) -> None:
        """ Show open dialog """

        dlg = ParameterDialog()
        dlg.setWindowTitle("Open")
        if dlg.exec_():
            file_name = dlg.filename.text()
            separator = dlg.separator
            decimal = dlg.decimal
            header = dlg.header
            index = dlg.index
        else:
            file_name = None

        if file_name:
            self.saveRecent(file_name)
            self.open_csv_file(file_name, separator, decimal, header, index)

    def onOpenRecentFile(self, file_name: str, sep=',', decimal='.') -> None:
        """ Open file from recent list, show open dialog """

        dlg = ParameterDialog(file_name, sep, decimal)
        dlg.setWindowTitle("Open")
        if dlg.exec_():
            file_name = dlg.filename.text()
            separator = dlg.separator
            decimal = dlg.decimal
            header = dlg.header
            index = dlg.index
        else:
            file_name = None

        if file_name:
            self.saveRecent(file_name)
            self.open_csv_file(file_name, separator, decimal, header, index)

    def open_csv_file(self, file_name: str, sep=',', decimal=".", header=True, index=True) -> None:
        """ Open csv file, load to tableview, set statusbar, enable close icon"""
        try:
            if header:
                my_header = 'infer'
            else:
                my_header = None

            if index:
                my_index = 0
            else:
                my_index = False

            print(my_header, my_index)
            data = pd.read_csv(file_name, sep=sep, decimal=decimal, header=my_header, index_col=my_index)
            self.df = data
            self.model = TableModel(self.df, self.round_num)
            self.labelStatus.setText(f"Rows: {self.df.shape[0]} Cols: {self.df.shape[1]}")
            self.table.setModel(self.model)
            if data.shape[0] > 0:
                self.table.selectRow(0)

            self.setButtons(True)
            self.setWindowTitle(self.app_title + ": " + file_name)
        except Exception as e:
            QMessageBox.warning(self, 'Error', f"Error loading the file:\n {file_name}")

    def setButtons(self, state: bool) -> None:
        """ Set state of buttons/actions """
        self.button_close.setEnabled(state)
        self.button_summary.setEnabled(state)
        self.button_info.setEnabled(state)
        self.button_resize.setEnabled(state)
        self.button_xlsx.setEnabled(state)
        self.button_sqlite.setEnabled(state)
        self.button_html.setEnabled(state)
        self.button_csv.setEnabled(state)
        self.button_nan.setEnabled(state)
        self.button_mark.setEnabled(state)

    def onResizeColumns(self) -> None:
        """Resize columns action, run from menu View->Resize columns"""
        self.table.resizeColumnsToContents()

    def onToolbarCloseButtonClick(self) -> None:
        """Clear tableview, set statusbar and disable toolbar close, summary and info icons"""
        self.table.setModel(None)
        self.df = None
        self.setButtons(False)
        self.setWindowTitle(self.app_title)
        self.labelStatus.setText("Rows: 0 Cols: 0")

    def onToolbarSummaryButtonClick(self) -> None:
        """Show Summary dialog"""
        dlg = SummaryDialog(self.df.describe())
        dlg.setWindowTitle("Summary")
        dlg.exec_()

    def onToolbarInfoButtonClick(self) -> None:
        """Show Info dialog"""
        # buf = io.StringIO()
        # self.df.info(buf=buf)
        # tmp = buf.getvalue()

        dlg = InfoDialog(self.df)
        dlg.setWindowTitle("Info")
        dlg.exec_()

    def onExportXlsx(self) -> None:
        """ Export data to xlsx file """
        file_name, _ = QFileDialog.getSaveFileName(self, 'Export to xlsx', '', ".xlsx(*.xlsx)")
        if file_name:
            self.df.to_excel(file_name, engine='xlsxwriter')

    def onExportSQLite(self) -> None:
        file_name, _ = QFileDialog.getSaveFileName(self, 'Export to sqlite db', '', ".sqlite(*.sqlite)")
        if file_name:
            engine = create_engine(f'sqlite:///{file_name}', echo=False)
            self.df.to_sql('csv_data', con=engine)

    def onExportHTML(self) -> None:
        """ Export data to HTML file """
        file_name, _ = QFileDialog.getSaveFileName(self, 'Export to HTML file', '', ".html(*.html)")
        if file_name:
            self.df.to_html(file_name)

    def onExportCSV(self) -> None:
        """ Export data to new CSV file """
        file_name, _ = QFileDialog.getSaveFileName(self, 'Export to CSV file', '', ".csv(*.csv)")
        if file_name:
            self.df.to_csv(file_name, sep=',', decimal='.')

    def onImportFromAPI(self) -> None:
        dlg = ApiDialog()
        dlg.setWindowTitle("Import a Data CSV via API")
        if dlg.exec_():
            file_name = dlg.filename.text()
            address = dlg.address.text()
        else:
            file_name = None

        if file_name and address:
            res, text = dataload.import_data_by_api(address)
            if res:
                with open(file_name, "w") as f:
                    f.write(text)
                self.onOpenRecentFile(file_name)
            else:
                QMessageBox.warning(self, "Error", text)

    def closeEvent(self, event) -> None:
        """ Quit application, ask user before """
        if not app_test:
            result = QMessageBox.question(
                self, self.app_title,
                "Are you sure you want to quit?",
                QMessageBox.Yes | QMessageBox.No,
            )

        if app_test or result == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def about(self) -> None:
        """ Show About dialog (info about application)"""
        dlg = AboutDialog()
        dlg.exec_()

    def openRecentFile(self) -> None:
        """ Open file from recent list action """
        action = self.sender()
        if action:
            self.onOpenRecentFile(action.data())

    def saveRecent(self, file_name) -> None:
        """ Save information about currently opened file, update recent list"""
        settings = QSettings('CSV_Viewer', 'CSV_Viewer')
        files = settings.value('recentFileList', [])

        try:
            files.remove(file_name)
        except ValueError:
            pass

        files.insert(0, file_name)
        del files[MainWindow.MaxRecentFiles:]

        settings.setValue('recentFileList', files)

        for widget in QtWidgets.QApplication.topLevelWidgets():
            if isinstance(widget, MainWindow):
                widget.updateRecentFileActions()

    def updateRecentFileActions(self) -> None:
        """ Update recent file list """
        settings = QSettings('CSV_Viewer', 'CSV_Viewer')
        files = settings.value('recentFileList', [])

        numRecentFiles = min(len(files), MainWindow.MaxRecentFiles)

        for i in range(numRecentFiles):
            text = "&%d %s" % (i + 1, self.strippedName(files[i]))
            self.recentFileActs[i].setText(text)
            self.recentFileActs[i].setData(files[i])
            self.recentFileActs[i].setVisible(True)

        for j in range(numRecentFiles, MainWindow.MaxRecentFiles):
            self.recentFileActs[j].setVisible(False)

        self.separatorAct.setVisible((numRecentFiles > 0))

    def strippedName(self, fullFileName: str) -> str:
        """ Return only file name, without path"""
        return QFileInfo(fullFileName).fileName()

    def showToolbar(self):
        """ show / hide main toolbar"""
        if self.toolbar.isHidden():
            self.toolbar.show()
        else:
            self.toolbar.hide()

    def onSettings(self):
        """ Round numbers to """
        n, result = QInputDialog.getInt(self, "Settings", "Round numbers to:", self.round_num, 0, 10, 1)
        if result and n != self.round_num:
            self.round_num = n
            self.settings.setValue('round_numbers', self.round_num)
            if self.df.shape[0] > 0:
                index = self.table.currentIndex()
                self.model = TableModel(self.df, self.round_num)
                self.table.setModel(self.model)
                self.table.selectRow(index.row())

    def onRemoveNaN(self):
        """ Remove rows with missing values """
        if self.df.shape[0] > 0:
            button = QMessageBox.question(self, "Remove NaN", "Remove rows with missing values?")
            if button == QMessageBox.Yes:
                self.df.dropna(axis=0, how='any', inplace=True)
                self.model = TableModel(self.df, self.round_num)
                self.table.setModel(self.model)
                self.table.selectRow(0)
                self.labelStatus.setText(f"Rows: {self.df.shape[0]} Cols: {self.df.shape[1]}")

    def onExportMarkdown(self):
        """ export to markdown table in thread """
        file_name, _ = QFileDialog.getSaveFileName(self, 'Export to Markdown file', '', ".md(*.md)")
        if file_name:
            worker = MarkdownWorker(file_name, self.df)
            worker.signals.progress.connect(self.update_progress)
            worker.signals.status.connect(self.update_status)
            self.threadpool.start(worker)

    def update_progress(self, progress):
        self.progress.setValue(progress)

    def update_status(self, status):
        if status:
            self.progress.show()
        else:
            self.progress.hide()
Ejemplo n.º 32
0
class AudioPlayerPage(QWidget):
    about_play_audio = pyqtSignal(str)

    def __init__(self):
        super().__init__()

        self.audio_list_widget = QListWidget()
        self.audio_list_widget.installEventFilter(self)
        self.audio_list_widget.itemDoubleClicked.connect(self.play)

        # TODO: playlist объединить с audio_list_widget (см примеры работы с QMediaPlayer)
        self.playlist = QMediaPlaylist()
        self.playlist.currentIndexChanged.connect(
            lambda row: self.audio_list_widget.setCurrentRow(row))

        # TODO: обрабатывать сигналы плеера: http://doc.qt.io/qt-5/qmediaplayer.html#signals
        self.player = QMediaPlayer()
        self.player.setPlaylist(self.playlist)
        self.player.currentMediaChanged.connect(
            lambda media: self.about_play_audio.emit(self.audio_list_widget.
                                                     currentItem().text()))

        if not self.player.isAvailable():
            # TODO: перевод
            text = "The QMediaPlayer object does not have a valid service.\n" \
                   "Please check the media service plugins are installed."

            log.warning(text)
            QMessageBox.warning(self, "Service not available", text)

            quit()

        self.controls = PlayerControls(self.player)
        self.controls.set_state(self.player.state())
        self.controls.set_volume(self.player.volume())
        self.controls.set_muted(self.controls.is_muted())

        self.controls.play_signal.connect(self.play)
        self.controls.pause_signal.connect(self.player.pause)
        self.controls.stop_signal.connect(self.player.stop)
        self.controls.next_signal.connect(self.playlist.next)
        self.controls.previous_signal.connect(self.playlist.previous)
        self.controls.change_volume_signal.connect(self.player.setVolume)
        self.controls.change_muting_signal.connect(self.player.setMuted)

        self.progress = QProgressBar()
        self.progress.hide()

        layout = QVBoxLayout()
        layout.addWidget(self.controls)
        layout.addWidget(self.audio_list_widget)
        layout.addWidget(self.progress)

        self.setLayout(layout)

        self.thread = LoadAudioListThread()
        self.thread.about_add_audio.connect(self._add_audio)
        self.thread.about_progress.connect(self.progress.setValue)
        self.thread.about_range_progress.connect(self.progress.setRange)
        self.thread.started.connect(self._start)
        self.thread.finished.connect(self._finished)

    def _add_audio(self, title, url):
        item = QListWidgetItem(title)
        item.setData(Qt.UserRole, url)
        self.audio_list_widget.addItem(item)
        self.playlist.addMedia(QMediaContent(QUrl(url)))

        # При добавлении первой аудизаписи, вызываем воспроизведение
        if self.audio_list_widget.count() == 1:
            self.audio_list_widget.setCurrentRow(0)
            self.playlist.setCurrentIndex(0)
            self.play()

    def _start(self):
        self.audio_list_widget.clear()
        self.playlist.clear()

        self.progress.show()

    def _finished(self):
        self.progress.hide()

    def fill(self, vk):
        self.thread.vk = vk

        # Если поток запущен, останавливаем его, иначе -- запускаем
        if self.thread.isRunning():
            self.thread.exit()
        else:
            self.thread.start()

    def play(self):
        if self.playlist.currentIndex() != self.audio_list_widget.currentRow():
            self.playlist.setCurrentIndex(self.audio_list_widget.currentRow())

        self.player.play()

    def eventFilter(self, obj, event):
        # Воспроизведение видео при клике на кнопки Enter/Return в плейлисте
        if obj == self.audio_list_widget and event.type(
        ) == QKeyEvent.KeyPress:
            if self.audio_list_widget.hasFocus() and event.key(
            ) == Qt.Key_Return or event.key() == Qt.Key_Enter:
                item = self.audio_list_widget.currentItem()
                if item is not None:
                    self.play()

        return super().eventFilter(obj, event)
Ejemplo n.º 33
0
class MyMainForm(QMainWindow, Ui_mainform.Ui_MainWindow):
    resized = QtCore.pyqtSignal()
    def __init__(self, parent=None):
        global cfg
        super(MyMainForm, self).__init__(parent)
        self.colorDict = {"grey": (211,211,211), "black": (0,0,0), "white": (255, 255, 255)}
        self.setupUi(self)
        self.current_image_list= None
        self.fontSize = self.fontSizeSlideBar.value()
        self.text_content = self.textWatermarkContentsLineEdit.text()
        self.dateEdit.setDate(datetime.datetime.now())
        self.fontSizeSlideBar.valueChanged.connect(self.DisplayFontSizeSlideBarValue)
        self.fontSize = self.fontSizeSlideBar.value()
        self.fontSizeLineEdit.setText(str(self.fontSizeSlideBar.value()))
        self.textWatermarkContentsLineEdit.textChanged.connect(self.GetTextContent)
        self.previewBtn.clicked.connect(self.StartImageWorkingThread)
        self.thread = Worker(self.current_image_list,self)
        self.thread.finishSignal.connect(self.ShowImageOnGraphicsView)        
        self.progressBar = QProgressBar()
        self.statusBar().addPermanentWidget(self.progressBar)
        self.progressBar.setRange(0, 1)
        self.progressBar.hide()
        self.choiceImageFilesBtn.clicked.connect(self.ShowFileDialog)
        self.previewBtn.clicked.connect(self.StartPreview)
        self.addWatermarksBtn.clicked.connect(self.StartAddImageWatermarksAndSave)
        self.transparentRate = self.spinBox.value()
        self.spinBox.valueChanged.connect(self.ChangeTransparentRate)
        self.defaultCurrentDateCb.clicked.connect(self.SetDateEditEnable)
        self.textWatermarkContentsLineEdit.setText(cfg.get("CONFIG","Text"))
        self.spinBox.setValue(int(cfg.getint("CONFIG","TransparentRate")))
        self.defaultCurrentDateCb.setChecked(cfg.getboolean("CONFIG","DefaultToday"))
        self.SetDateEditEnable()
        self.fontSizeSlideBar.setValue(int(cfg.getint("CONFIG","FontSize")))
        self.realtimePreviewCb.setChecked(cfg.getboolean("CONFIG", "RealtimePreview"))
        self.radioBlack.clicked.connect(self.ChangeWaterMarkColor)
        self.radioWhite.clicked.connect(self.ChangeWaterMarkColor)
        self.radioGrey.clicked.connect(self.ChangeWaterMarkColor)
        self.dateEdit.dateChanged.connect(self.StartPreview)
        watermark_color = cfg.get("CONFIG", "Color")
        if watermark_color == "black":
            self.watermark_color = self.colorDict["black"]
            self.radioBlack.setChecked(True)
        elif watermark_color == "white":
            self.watermark_color = self.colorDict["white"]
            self.radioWhite.setChecked(True)
        else:
            self.watermark_color = self.colorDict["grey"]
            self.radioGrey.setChecked(True)
        if self.current_image_list  == None:
            # self.realtimePreviewCb.setEnabled(False)
            self.previewBtn.setEnabled(False)
            self.addWatermarksBtn.setEnabled(False)
    
    def ChangeWaterMarkColor(self):
        global cfg
        if self.radioBlack.isChecked():
            self.watermark_color = self.colorDict["black"]
            cfg.set("CONFIG", "Color", "black")
        elif self.radioWhite.isChecked():
            self.watermark_color = self.colorDict["white"]
            cfg.set("CONFIG", "Color", "white")
        else:
            self.watermark_color = self.colorDict["grey"]
            cfg.set("CONFIG", "Color", "grey")
        cfg.write(open("config.ini", "w"))
        self.thread.form = self
        self.StartPreview()

    def ChangeTransparentRate(self):
        global cfg
        self.transparentRate = self.spinBox.value()
        cfg.set("CONFIG", "TransparentRate", str(self.transparentRate))
        cfg.write(open("config.ini", "w"))
        self.thread.form = self
        self.StartPreview()
    
    def SetDateEditEnable(self):
        global cfg
        if self.defaultCurrentDateCb.isChecked():
            self.dateEdit.setEnabled(False)
            self.dateEdit.setDate(datetime.datetime.now())
        else:
            self.dateEdit.setEnabled(True)
        cfg.set("CONFIG", "DefaultToday", str(self.defaultCurrentDateCb.isChecked()))
        cfg.write(open("config.ini", "w"))

    def ShowFileDialog(self):
        self.current_image_list = QFileDialog.getOpenFileNames(self, '选择图片文件', "" , "JPG 文件 (*.jpg *.jpeg)")[0]
        if self.current_image_list != None and len(self.current_image_list) > 0:
            # self.realtimePreviewCb.setEnabled(True)
            self.previewBtn.setEnabled(True)
            self.addWatermarksBtn.setEnabled(True)
            self.thread.image_list = self.current_image_list
            print(self.current_image_list)
            self.save_image_path = os.path.abspath(os.path.dirname(self.current_image_list[0])) + "\\new\\"
            if self.realtimePreviewCb.isChecked():
                self.StartPreview()
        else:
            self.current_image_list = None
            # self.realtimePreviewCb.setEnabled(False)
            self.previewBtn.setEnabled(False)
            self.addWatermarksBtn.setEnabled(False)
            image_scene = QGraphicsScene()
            self.graphicsView.setScene(image_scene)
            # self.absFileName = os.path.basename(self.current_image_list[0])

    def ShowImageOnGraphicsView(self, count, pixmap, isPreview):
        pixmapItem = QGraphicsPixmapItem(pixmap)
        image_scene = QGraphicsScene()
        image_scene.addItem(pixmapItem)
        if isPreview == False:
            self.statusBar().showMessage("总计图片: {} 张,正在处理第 {} 张".format(len(self.current_image_list),count))
            self.progressBar.show()
            self.progressBar.setMaximum(len(self.current_image_list))
            self.progressBar.setValue(count)
        self.graphicsView.setScene(image_scene)
        self.graphicsView.fitInView(pixmapItem,QtCore.Qt.AspectRatioMode.KeepAspectRatio)  
        if len(self.current_image_list) == count:
            self.statusBar().showMessage("图片处理完成。")
            self.progressBar.hide()
            self.previewBtn.setEnabled(True)
            self.textWatermarkContentsLineEdit.setEnabled(True)
            self.fontSizeSlideBar.setEnabled(True)
            self.defaultCurrentDateCb.setEnabled(True)
            self.realtimePreviewCb.setEnabled(True)
            self.spinBox.setEnabled(True)
            self.radioGrey.setEnabled(True)
            self.radioBlack.setEnabled(True)
            self.radioWhite.setEnabled(True)
            self.addWatermarksBtn.setEnabled(True)

    def DisplayFontSizeSlideBarValue(self):
        global cfg
        self.fontSizeLineEdit.setText(str(self.fontSizeSlideBar.value()))
        self.fontSize = self.fontSizeSlideBar.value()
        cfg.set("CONFIG", "FontSize", str(self.fontSize))
        cfg.write(open("config.ini", "w"))
        self.thread.fontSize = self.fontSize
        self.StartPreview()
    
    def GetTextContent(self):
        self.text_content =  self.textWatermarkContentsLineEdit.text()
        cfg.set("CONFIG", "text", self.text_content)
        cfg.write(open("config.ini", "w"))
        self.thread.text_content = self.text_content
        self.StartPreview()
    
    def StartPreview(self):
        if self.realtimePreviewCb.isChecked() and self.current_image_list != None:
            self.statusBar().showMessage('')
            self.StartImageWorkingThread()
        elif self.realtimePreviewCb.isChecked():
            self.statusBar().showMessage("请先选择图片文件方可实时预览。")
    
    def StartImageWorkingThread(self):
        self.thread.isPreview = True
        self.thread.form = self
        self.thread.start()
    
    def StartAddImageWatermarksAndSave(self):
        self.thread.isPreview = False
        self.addWatermarksBtn.setEnabled(False)
        self.previewBtn.setEnabled(False)
        self.textWatermarkContentsLineEdit.setEnabled(False)
        self.fontSizeSlideBar.setEnabled(False)
        self.defaultCurrentDateCb.setEnabled(False)
        self.realtimePreviewCb.setEnabled(False)
        self.spinBox.setEnabled(False)
        self.radioGrey.setEnabled(False)
        self.radioBlack.setEnabled(False)
        self.radioWhite.setEnabled(False)
        self.thread.start()
Ejemplo n.º 34
0
class Dino(QThread):
    trigger = pyqtSignal(MoveMyImageEvent)
    sizetrigger = pyqtSignal(ChangeSizeImageEvent)
    atacktrigger = pyqtSignal(Atacar)
    bonustrigger = pyqtSignal(Bonus)

    lista_threads_activos = []
    id = 0

    def __init__(self, parent, x, y, foto):
        super().__init__()
        self.parent = parent
        self.foto = foto
        #Crea el atributo dentro de la otra ventana
        self.image = QLabel(parent)
        self.pro_bar = QProgressBar(parent)
        self.pro_bar.setTextVisible(False)
        self.crecio_este_nivel = False
        self.id = Dino.id
        Dino.id += 1
        self.rango_vision = 0
        self.rango_escape = 0
        if foto == 'malo':
            #Nos dá el tamaño del monstruo dependiendo de la distribución y del nivel del juego
            tamano = retornar_tamano(self.parent) * 30
            self._size = (tamano, tamano)
            self.image.setGeometry(x, y, tamano, tamano)
            self.pro_bar.setGeometry(x, y - 20, tamano, 10)
            self.lvl_size = tamano / 30
        else:
            tamano = 60
            #Tamaño en la interfaz
            self._size = (tamano, tamano)
            self.image.setGeometry(x, y, tamano, tamano)
            self.pro_bar.setGeometry(x, y - 20, tamano, 10)
            #Nivel de tamaño
            self.lvl_size = 2
        #Lo que le pasamos a la tienda
        self.bonus_correr = 0
        self.bonus_vida = 0
        self.bonus_atacar = 0
        #Inconsistencia en el enunciado, luego desde la tienda lo multiuplico por 1.1
        self.vida_max = (((self.lvl_size) * 20) + 100)
        self._vida = self.vida_max
        self.muerto = False
        #velocidad ataque inicial
        self.ataque = round(self.lvl_size * (1 / 10) * self.vida_max, 0)
        #velocidad movimiento inicial
        if foto == 'malo':
            self.velocidad = 1
        if foto == 'user':
            self.velocidad = 0.1
        self.vel_ataque = 1
        self.ratio_vel_ataque = self.vel_ataque / self.velocidad
        self.cont = 0
        #Para los safes zones
        self.atacable = True
        #Se crea una lista cada segundo con las distancias de todos los enemigos al personaje principal
        self.distancias = list
        self._nro_foto = ('c', 1)  #C de caminar, tiene 16
        #self.nro_foto = ('a', 1)        #a de atacar, tiene 8
        #self.nro_foto = ('m', 1)        #M de morir 15
        if self.foto == 'user':
            fase = 'Assets/principal/{} ({}).png'.format(
                str(self.nro_foto[0]), str(self.nro_foto[1]))
        else:
            fase = 'Assets/enemigo/{} ({}).png'.format(str(self.nro_foto[0]),
                                                       str(self.nro_foto[1]))
        print(fase)
        self.pixmap = QPixmap(fase)
        self.image.setPixmap(self.pixmap)
        self.image.setScaledContents(True)
        self.pro_bar.setValue((self.vida / self.vida_max) * 100)
        self.image.show()
        self.pro_bar.show()
        self.image.setVisible(True)
        self.pro_bar.setVisible(True)
        self.trigger.connect(parent.actualizar_imagen)
        self.sizetrigger.connect(parent.agrandar_imagen)
        self.atacktrigger.connect(parent.atacar)
        self.bonustrigger.connect(parent.bonuses)
        self.rotation = 0

        self.__position = (x, y)
        self.position = (x, y)
        self.pos_centro = ""
        self.calcular_zona()

        self.lista_mov = []
        prox_apar(self.parent)

    @property
    def vida(self):
        return self._vida

    @vida.setter
    def vida(self, value):
        if value <= 0:
            self.muerto = True
        else:
            self._vida = value

    @property
    def position(self):
        return self.__position

    @position.setter
    def position(self, value):
        ancho = int(self.parent.centralwidget.size().width()) - self.size[0]
        alto_barra = int(self.parent.pro_bar.size().height()) + 23 + int(
            self.parent.score_no.size().height())
        largo = int(
            self.parent.centralwidget.size().height()) - self.size[0] + 21

        if value[1] > alto_barra:
            if value[0] > 0:
                if value[0] < ancho:
                    if value[1] < largo:
                        self.__position = value
                        self.trigger.emit(
                            MoveMyImageEvent(self.image, self.position[0],
                                             self.position[1]))
                        self.trigger.emit(
                            MoveMyImageEvent(self.pro_bar, self.position[0],
                                             self.position[1] - 17))
                    else:
                        self.__position = (value[0], largo)
                        self.trigger.emit(
                            MoveMyImageEvent(self.image, self.position[0],
                                             self.position[1]))
                        self.trigger.emit(
                            MoveMyImageEvent(self.pro_bar, self.position[0],
                                             self.position[1] - 17))
                elif value[0] >= ancho and value[1] <= largo:
                    self.__position = (ancho, value[1])
                    self.trigger.emit(
                        MoveMyImageEvent(self.image, self.position[0],
                                         self.position[1]))
                    self.trigger.emit(
                        MoveMyImageEvent(self.pro_bar, self.position[0],
                                         self.position[1] - 17))
            elif value[0] <= 0 and value[0] <= ancho and value[1] <= largo:
                self.__position = (0, value[1])
                self.trigger.emit(
                    MoveMyImageEvent(self.image, self.position[0],
                                     self.position[1]))
                self.trigger.emit(
                    MoveMyImageEvent(self.pro_bar, self.position[0],
                                     self.position[1] - 17))
        elif value[1] <= alto_barra and value[0] >= 0 and value[0] <= ancho:
            self.__position = (value[0], alto_barra)
            self.trigger.emit(
                MoveMyImageEvent(self.image, self.position[0],
                                 self.position[1]))
            self.trigger.emit(
                MoveMyImageEvent(self.pro_bar, self.position[0],
                                 self.position[1] - 17))
        #Cada vez que se mueve se calcula el centro del circulo nuevamente
        self.calcular_zona()
        # print(self.pos_centro)
        # print(self.position)
        # print(self.size)

    @property
    def size(self):
        return self._size

    @size.setter
    def size(self, value):
        if value[0] <= 300:
            self._size = value
            self.sizetrigger.emit(
                ChangeSizeImageEvent(image=self.image,
                                     x=self.position[0],
                                     y=self.position[1],
                                     sizex=self.size[0],
                                     sizey=self.size[1]))

    @property
    def nro_foto(self):
        return self._nro_foto

    @nro_foto.setter
    def nro_foto(self, value):
        if self.foto == 'user':
            if value[0] == 'c':
                if value[1] == 9:
                    self._nro_foto = ('c', 1)
                else:
                    self._nro_foto = value
            if value[0] == 'a':
                if value[1] == 9:
                    self._nro_foto = ('a', 0)
                else:
                    self._nro_foto = value
        if self.foto == 'malo':
            if value[0] == 'c':
                if value[1] == 9:
                    self._nro_foto = ('c', 1)
                else:
                    self._nro_foto = value

    def crece(self):
        self.size = (self.size[0] + 30, self.size[1] + 30)
        self.lvl_size = self.size[0] / 30
        self.calcular_zona()
        self.vida_max = (((self.lvl_size) * 20) + 100)
        self.ataque = round(self.lvl_size * (1 / 10) * self.vida_max, 0)
        self.pro_bar.setGeometry(self.position[0], self.position[1] - 20,
                                 self.lvl_size * 30, 10)

    def calcular_zona(self):
        """Esta función nos va a entregar el centro de un círculo alrededor del personaje
        que nos va a ayudar a darnos cuenta cuando hay un choque o un acercamiento"""
        sizes = self.image.size()
        alto = sizes.height()
        ancho = sizes.width()
        #coordenadas de la esquina superior derecha
        corx = self.position[0]
        cory = self.position[1]
        #circulo de centro(cirx, ciry)
        cirx = corx + (ancho / 2)
        ciry = cory + (alto / 2)
        self.radio = (((self.size[0] / 2)**2 + (self.size[1] / 2)**2)**(1 / 2))
        self.pos_centro = (cirx, ciry)

    def check_dir(self):
        if 'up' in self.lista_mov:
            self.position = (self.position[0] +
                             10 * math.cos(math.radians(self.rotation)),
                             self.position[1] +
                             10 * math.sin(math.radians(self.rotation)))
        if 'down' in self.lista_mov:
            self.position = (self.position[0] -
                             10 * math.cos(math.radians(self.rotation)),
                             self.position[1] -
                             10 * math.sin(math.radians(self.rotation)))
        if 'right' in self.lista_mov and self.atacable:
            self.rotation += 5
        if 'left' in self.lista_mov and self.atacable:
            self.rotation -= 5
        if self.atacable:
            transform = QTransform().rotate(self.rotation)

        #Caminar
        self.nro_foto = (self.nro_foto[0], self.nro_foto[1] + 1)
        self.pixmap = QPixmap('Assets/principal/{} ({}).png'.format(
            str(self.nro_foto[0]), str(self.nro_foto[1])))
        pixmap = self.pixmap.transformed(transform)
        self.image.setPixmap(pixmap)
        self.image.show()

    def check_crash(self):
        elem = ''
        if not self.muerto:
            for i in self.distancias:
                '''self.distancias contiene una lista de tuplas [(distancia, objeto)]'''
                if i[0] < i[1].radio + self.radio and not i[1].muerto:
                    if i[1].foto == 'malo' and self.foto == 'user':
                        print('Choque con el {} número {}'.format(
                            i[1].foto, i[1].id))
                        self.atacktrigger.emit(Atacar(self, i[1]))

                    if self.foto == 'user' and i[1].foto == 'extra':
                        print('Agarramos el elemento {}'.format(i[1].elem))
                        self.bonustrigger.emit(Bonus(self, i[1]))
                        elem = i[1].elem
                        if elem == 'safe_zone':
                            self.atacable = False

                    if self.foto == 'malo' and i[1].foto == 'user':
                        self.atacktrigger.emit(Atacar(self, i[1]))
                        print('ataque de verdad')

                if elem != 'safe_zone':
                    self.atacable = True

    def malo_moverse(self):
        '''Solo para los malos, estos son los movimientos aleatorios + los que persiguen a Dino(El personaje principal)'''
        self.rango_vision = self.lvl_size * 30 + self.radio
        self.rango_escape = self.rango_vision * 1.5 + self.radio

        self.distancias = [(distancia(self.pos_centro, i.pos_centro), i)
                           for i in Dino.lista_threads_activos
                           if i.muerto == False and i.foto == 'user']
        obj_in_rango_vision = [
            i for i in self.distancias if i[0] < self.rango_vision
        ]
        obj_in_rango_escape = [
            i for i in self.distancias if i[0] < self.rango_escape
        ]
        obj_in_ataque = [
            i for i in self.distancias if i[0] < i[1].radio + self.radio
        ]

        if obj_in_rango_vision == []:
            #Aca definimos el movimiento aleatorio
            prob_doblar = random()
            if prob_doblar < 0.25:
                self.rotation += 22.5

            #Caminar sin apuro#Caminar
            transform = QTransform().rotate(self.rotation)
            self.nro_foto = (self.nro_foto[0], self.nro_foto[1] + 1)
            self.pixmap = QPixmap('Assets/enemigo/{} ({}).png'.format(
                str(self.nro_foto[0]), str(self.nro_foto[1])))
            pixmap = self.pixmap.transformed(transform)
            self.image.setPixmap(pixmap)
            self.image.show()

            self.position = (self.position[0] +
                             10 * math.cos(math.radians(self.rotation)),
                             self.position[1] +
                             10 * math.sin(math.radians(self.rotation)))

        #Dentro Rango Vision
        #escapa
        if len(obj_in_rango_vision) >= 1:
            #malo tiene  menor nivel
            if self.lvl_size < obj_in_rango_vision[0][1].lvl_size:
                dino = obj_in_rango_vision[0][1]
                while len(obj_in_rango_escape
                          ) > 0 and dino.parent.seguir and not self.muerto:
                    print('Escape_Mode')
                    #Persecución
                    dir_ataque = (math.atan2(
                        dino.position[1] - self.position[1],
                        dino.position[0] - self.position[0]))
                    self.rotation = dir_ataque
                    transform = QTransform().rotate(
                        math.degrees(self.rotation) + 180)
                    pixmap = self.pixmap.transformed(transform)
                    self.image.setPixmap(pixmap)
                    self.image.show()
                    self.position = (self.position[0] +
                                     10 * math.cos((self.rotation) + math.pi),
                                     self.position[1] +
                                     10 * math.sin((self.rotation) + math.pi))
                    self.distancias = [
                        (distancia(self.pos_centro, i.pos_centro), i)
                        for i in Dino.lista_threads_activos
                        if i.muerto == False and i.foto == 'user'
                    ]
                    obj_in_rango_vision = [
                        i for i in self.distancias if i[0] < self.rango_vision
                    ]
                    obj_in_rango_escape = [
                        i for i in self.distancias if i[0] < self.rango_escape
                    ]
                    obj_in_ataque = [
                        i for i in self.distancias
                        if i[0] < i[1].radio + self.radio
                    ]
                    QTest.qWait(1000)
                    self.check_crash()

                    #Caminar
                    self.nro_foto = (self.nro_foto[0], self.nro_foto[1] + 1)
                    self.pixmap = QPixmap('Assets/enemigo/{} ({}).png'.format(
                        str(self.nro_foto[0]), str(self.nro_foto[1])))
                    pixmap = self.pixmap.transformed(transform)
                    self.image.setPixmap(pixmap)
                    self.image.show()

            #malo tiene Mayor nivel
            elif self.lvl_size > obj_in_rango_vision[0][
                    1].lvl_size and not self.muerto:
                dino = obj_in_rango_vision[0][1]
                while len(obj_in_rango_escape) > 0 and dino.parent.seguir:
                    print('persuit mode')
                    #Persecución
                    dir_ataque = (math.atan2(
                        dino.position[1] - self.position[1],
                        dino.position[0] - self.position[0]))
                    self.rotation = dir_ataque
                    transform = QTransform().rotate(math.degrees(
                        self.rotation))
                    pixmap = self.pixmap.transformed(transform)
                    self.image.setPixmap(pixmap)
                    self.image.show()

                    self.position = (self.position[0] + 10 * math.cos(
                        (self.rotation)), self.position[1] + 10 * math.sin(
                            (self.rotation)))
                    QTest.qWait(1000)
                    self.distancias = [
                        (distancia(self.pos_centro, i.pos_centro), i)
                        for i in Dino.lista_threads_activos
                        if i.muerto == False and i.foto == 'user'
                    ]
                    obj_in_rango_vision = [
                        i for i in self.distancias if i[0] < self.rango_vision
                    ]
                    obj_in_rango_escape = [
                        i for i in self.distancias if i[0] < self.rango_escape
                    ]
                    obj_in_ataque = [
                        i for i in self.distancias
                        if i[0] < i[1].radio + self.radio
                    ]
                    self.check_crash()
                    #Caminar
                    self.nro_foto = (self.nro_foto[0], self.nro_foto[1] + 1)
                    self.pixmap = QPixmap('Assets/enemigo/{} ({}).png'.format(
                        str(self.nro_foto[0]), str(self.nro_foto[1])))
                    pixmap = self.pixmap.transformed(transform)
                    self.image.setPixmap(pixmap)
                    self.image.show()

            #Igual nivel
            elif self.lvl_size == obj_in_rango_vision[0][
                    1].lvl_size and not self.muerto:
                deci = random()
                if deci > 0.5:
                    defensa = 1
                else:
                    defensa = 0
                #Si defensa es 1 defiende
                dino = obj_in_rango_vision[0][1]
                while len(obj_in_rango_escape
                          ) > 0 and dino.parent.seguir and not self.muerto:
                    if defensa == 0:
                        print('persuit mode')
                    else:
                        print('run_mode')
                    #Persecución
                    dir_ataque = (math.atan2(
                        dino.position[1] - self.position[1],
                        dino.position[0] - self.position[0]))
                    self.rotation = dir_ataque
                    transform = QTransform().rotate(
                        math.degrees(self.rotation) + 180 * defensa)
                    pixmap = self.pixmap.transformed(transform)
                    self.image.setPixmap(pixmap)
                    self.image.show()

                    self.position = (
                        self.position[0] +
                        10 * math.cos((self.rotation) + math.pi * defensa),
                        self.position[1] +
                        10 * math.sin((self.rotation) + math.pi * defensa))
                    QTest.qWait(1000)
                    self.distancias = [
                        (distancia(self.pos_centro, i.pos_centro), i)
                        for i in Dino.lista_threads_activos
                        if i.muerto == False and i.foto == 'user'
                    ]
                    obj_in_rango_vision = [
                        i for i in self.distancias if i[0] < self.rango_vision
                    ]
                    obj_in_rango_escape = [
                        i for i in self.distancias if i[0] < self.rango_escape
                    ]
                    obj_in_ataque = [
                        i for i in self.distancias
                        if i[0] < i[1].radio + self.radio
                    ]
                    self.check_crash()
                    #Caminar
                    self.nro_foto = (self.nro_foto[0], self.nro_foto[1] + 1)
                    self.pixmap = QPixmap('Assets/enemigo/{} ({}).png'.format(
                        str(self.nro_foto[0]), str(self.nro_foto[1])))
                    pixmap = self.pixmap.transformed(transform)
                    self.image.setPixmap(pixmap)
                    self.image.show()

    def run(self):
        while not self.muerto:
            if self.parent.seguir:
                self.cont += 1
                # self.largo_max = self.parent.pro_bar.Length()
                QTest.qWait(self.velocidad * 1000)
                #Calcula las distancias entre todos los centros con respecto al personaje principal
                #Le sumamos 15 para que el choque se vea más real
                if self.foto == 'user':
                    self.distancias = [(distancia(self.pos_centro,
                                                  i.pos_centro), i)
                                       for i in Dino.lista_threads_activos
                                       if i.muerto == False and i != self]
                    self.ratio_vel_ataque = self.vel_ataque / self.velocidad
                    if self.cont > self.ratio_vel_ataque:
                        self.cont = 0
                        self.check_crash()
                    if not self.atacable:
                        self.image.hide()
                        #self.pro_bar.hide(), Este esconde también la barra de nivel, pero me gusta mas con
                    if self.atacable:
                        #self.pro_bar.show()
                        transform = QTransform().rotate(self.rotation)
                        pixmap = self.pixmap.transformed(transform)
                        self.image.setPixmap(pixmap)
                        self.image.show()

                    self.check_dir()
                    #Checkea si tiene que girar o moverse
                    #Se resetea la lista de movimientos
                    self.lista_mov = []

                if self.foto == 'malo':
                    self.malo_moverse()

        #Animación de la muerte
        if self.foto == 'user':
            carpeta = 'principal'
        else:
            carpeta = 'enemigo'

        for i in range(15):
            transform = QTransform().rotate(self.rotation)
            self.pixmap = QPixmap('Assets/{}/{} ({}).png'.format(
                carpeta, str('m'), str(i)))
            pixmap = self.pixmap.transformed(transform)
            self.image.setPixmap(pixmap)
            self.image.show()
            QTest.qWait(100)

        self.image.hide()
        self.pro_bar.hide()

    def __repr__(self):
        return self.foto
Ejemplo n.º 35
0
class Widget(QMainWindow):
    loaded_signal = pyqtSignal()
    progress_bar = pyqtSignal(int)
    exception_signal = pyqtSignal(Exception)

    def __init__(self):
        super().__init__()
        self.pbar = QProgressBar(self)
        self.pbar.setGeometry(30, 40, 200, 25)
        self.pbar.setValue(0)
        self.pbar.hide()
        self.isOpened = False
        self.is_loading = False
        self.img = QLabel()
        self.form_widget = CentralWidget(self)
        self.setCentralWidget(self.form_widget)

        self.progress_bar.connect(self.pbar.setValue)
        self.exception_signal.connect(self.show_error)
        self.loaded_signal.connect(self.set_gif_settings)

        self.gifinfo = None
        self.gif_id = 0

        self.create_menubar()

        self.scrTimer = QTimer(self)
        self.scrTimer.setInterval(50)
        self.scrTimer.timeout.connect(self.timerEvent)

        self.pal = self.form_widget.isPaused.palette()
        self.pal.setColor(QPalette.WindowText, QColor("red"))
        self.form_widget.isPaused.setPalette(self.pal)
        self.frames = [QPixmap()]

    def show_error(self, e):
        self.test = QMessageBox(self)
        self.test.setWindowModality(Qt.ApplicationModal)
        self.test.setWindowTitle('Error')
        self.test.setIcon(QMessageBox.Critical)
        self.test.setText(str(e))
        self.test.setStandardButtons(QMessageBox.Ok)
        self.test.show()
        self.pbar.hide()
        self.is_loading = False

    def create_menubar(self):
        main_menu = self.menuBar()

        file_menu = main_menu.addMenu('File')
        open_button = QAction('Open', self)
        open_button.setShortcut('Ctrl+O')
        open_button.triggered.connect(self.open_gif)
        close_button = QAction('Close', self)
        close_button.setShortcut('Ctrl+C')
        close_button.triggered.connect(self.close_gif)
        file_menu.addAction(open_button)
        file_menu.addAction(close_button)

        frame_menu = main_menu.addMenu('Frame')
        prev_button = QAction('Prev', self)
        prev_button.setShortcut('Left')
        prev_button.triggered.connect(self.prev_frame)
        pause_button = QAction('Play/Pause', self)
        pause_button.setShortcut('Space')
        pause_button.triggered.connect(self.pause_gif)
        next_button = QAction('Next', self)
        next_button.setShortcut('Right')
        next_button.triggered.connect(self.next_frame)
        frame_menu.addAction(prev_button)
        frame_menu.addAction(pause_button)
        frame_menu.addAction(next_button)

        play_menu = main_menu.addMenu('Play')
        dspeed_button = QAction('Speed -', self)
        dspeed_button.setShortcut('-')
        dspeed_button.triggered.connect(self.dspeed_gif)
        uspeed_button = QAction('Speed +', self)
        uspeed_button.setShortcut('+')
        uspeed_button.triggered.connect(self.uspeed_gif)
        play_menu.addAction(dspeed_button)
        play_menu.addAction(uspeed_button)

        return main_menu

    def open_gif(self):
        if self.is_loading:
            return
        self.is_loading = True
        self.fname = QFileDialog.getOpenFileName(
            self,
            'Open file',
            options=QFileDialog.DontUseNativeDialog)[0]
        if not self.fname:
            self.is_loading = False
            return
        self.close_gif()
        self.pbar.show()
        self.update()
        self.t = SomeThread(self.fname, self)
        self.t.start()

    def set_gif_settings(self):
        self.form_widget.isPaused.setText('Play')
        self.pal.setColor(QPalette.WindowText, QColor("green"))
        self.form_widget.isPaused.setPalette(self.pal)
        fps = round(1000 / self.scrTimer.interval())
        self.form_widget.fps.setText('FPS: {}'.format(fps))
        frames_length = len(self.gifinfo.frames)
        self.form_widget.frames.setText('Frame: 1/{}'.format(frames_length))
        self.isOpened = True
        width = int(self.gifinfo.width, 16)
        height = int(self.gifinfo.height, 16)
        width = width + 18 if width + 18 > 300 else 300
        height = height + 74 if height + 74 > 300 else 300
        self.setMinimumSize(width, height)
        self.resize(width, height)
        self.setWindowTitle(self.fname)
        self.pbar.hide()
        self.pbar.setValue(0)
        self.scrTimer.start()
        self.is_loading = False

    def close_gif(self):
        self.scrTimer.stop()
        self.gif_id = 0
        self.isOpened = False
        self.frames = [QPixmap(QImage().fill(QColor('#ffffff')))]
        self.form_widget.fps.setText('FPS: 0')
        self.form_widget.frames.setText('Frames: 0/0')
        self.form_widget.isPaused.setText('Pause')
        self.pal.setColor(QPalette.WindowText, QColor("red"))
        self.form_widget.isPaused.setPalette(self.pal)
        self.setMinimumSize(300, 300)
        self.resize(300, 300)
        self.setWindowTitle('GIF')
        self.update()

    def pause_gif(self):
        if not self.isOpened:
            return
        if self.scrTimer.isActive():
            self.scrTimer.stop()
        else:
            self.scrTimer.start()
        self.change_pause_text()

    def change_pause_text(self):
        if self.scrTimer.isActive():
            self.form_widget.isPaused.setText('Play')
            self.form_widget.isPaused.adjustSize()
            self.pal.setColor(QPalette.WindowText, QColor("green"))
            self.form_widget.isPaused.setPalette(self.pal)
        else:
            self.form_widget.isPaused.setText('Pause')
            self.form_widget.isPaused.adjustSize()
            self.pal.setColor(QPalette.WindowText, QColor("red"))
            self.form_widget.isPaused.setPalette(self.pal)

    def prev_frame(self):
        if not self.isOpened:
            return
        self.scrTimer.stop()
        if self.gif_id:
            self.gif_id -= 1
        else:
            self.gif_id = len(self.gifinfo.images) - 1
        self.set_frames_text()
        self.change_pause_text()
        self.update()

    def next_frame(self):
        if not self.isOpened:
            return
        self.scrTimer.stop()
        self.change_pause_text()
        if self.gif_id != len(self.gifinfo.frames) - 1:
            self.gif_id += 1
        else:
            self.gif_id = 0
        self.set_frames_text()
        self.update()

    def set_frames_text(self):
        frames_text = 'Frame: {}/{}'.format(self.gif_id + 1,
                                            len(self.gifinfo.frames))
        self.form_widget.frames.setText(frames_text)

    def set_fps_text(self):
        fps_text = 'FPS: {}'.format(round(1000 / self.scrTimer.interval()))
        self.form_widget.fps.setText(fps_text)

    def uspeed_gif(self):
        if not self.isOpened:
            return
        current_interval = self.scrTimer.interval()
        possible_fps = 1000 / current_interval + 1
        if possible_fps > 20:
            self.scrTimer.setInterval(50)
        else:
            self.scrTimer.setInterval(round(1000 / possible_fps))
        self.set_fps_text()

    def dspeed_gif(self):
        if not self.isOpened:
            return
        current_interval = self.scrTimer.interval()
        possible_fps = 1000 / current_interval - 1
        if possible_fps < 1:
            self.scrTimer.setInterval(1000)
        else:
            self.scrTimer.setInterval(round(1000 / possible_fps))
        self.set_fps_text()

    def timerEvent(self):
        self.gif_id = (self.gif_id + 1) % len(self.gifinfo.images)
        self.set_frames_text()
        self.update()

    def paintEvent(self, event):
        super().paintEvent(event)
        self.img.setPixmap(self.frames[self.gif_id])

    def get_all_pixmaps(self):
        result = []
        count = len(self.gifinfo.frames)
        all_percents = 70
        z = 0
        all = int(self.gifinfo.height, 16) * count
        for t in self.gifinfo.frames:
            frame = QImage(int(self.gifinfo.width, 16),
                           int(self.gifinfo.height, 16),
                           QImage.Format_RGB32)
            y = 0
            for i in t:
                x = 0
                for j in i:
                    frame.setPixelColor(x, y, QColor('#' + j))
                    x += 1
                y += 1

                z += 1
                self.progress_bar.emit(all_percents * z / all + 30)
            result.append(QPixmap(frame))
            self.progress_bar.emit(all_percents * z / all + 30)
        return result
Ejemplo n.º 36
0
class XNCStatusBar(QStatusBar):

    def __init__(self, parent=None):
        super(XNCStatusBar, self).__init__(parent)
        # state vars
        self.world = XNovaWorld_instance()
        # initialization
        self.setSizeGripEnabled(True)
        # sub-widgets
        # progressbar
        self._progressbar = QProgressBar(self)
        self._progressbar.hide()
        self._progressbar.setValue(0)
        self._progressbar.setRange(0, 99)
        # online players counter
        self._lbl_online = QLabel(self.tr('Online') + ': 0', self)
        # label with loading.gif
        self._loading_gif = QMovie(':/i/loading.gif')
        self._lbl_loading = QLabel(self)
        self._lbl_loading.setMovie(self._loading_gif)
        self._lbl_loading.hide()
        # testing only
        self._btn_runscript = QPushButton('Run script', self)
        self._btn_runscript.clicked.connect(self.on_run_script)
        self.addPermanentWidget(self._btn_runscript)
        #
        self.addPermanentWidget(self._lbl_loading)
        self.addPermanentWidget(self._lbl_online)  # should be las right widget
        self.show()

    def set_status(self, msg: str, timeout: int=0):
        self.showMessage(msg, timeout)

    def set_loading_status(self, loading: bool):
        if loading:
            self._lbl_loading.show()
            self._loading_gif.start()
        else:
            self._loading_gif.stop()
            self._lbl_loading.hide()

    def set_world_load_progress(self, comment: str, progress: int):
        """
        Display world load progress in status bar
        :param comment: string comment of what is currently loading
        :param progress: percent progress, or -1 to disable
        """
        if progress != -1:
            if not self._progressbar.isVisible():
                self.insertPermanentWidget(0, self._progressbar)
                self._progressbar.show()
            msg = self.tr('Loading world') + ' ({0}%) {1}...'.format(progress, comment)
            logger.debug(msg)
            self._progressbar.setValue(progress)
            self.set_status(msg)
        else:
            self.removeWidget(self._progressbar)
            self._progressbar.hide()
            self._progressbar.reset()
            self.clearMessage()

    def update_online_players_count(self):
        op = self.world.get_online_players()
        self._lbl_online.setText(self.tr('Online') + ': {0}'.format(op))

# some functions may be useful, documentation:
# void QStatusBar::clearMessage()
# void QStatusBar::addPermanentWidget(QWidget * widget, int stretch = 0)
# void QStatusBar::addWidget(QWidget * widget, int stretch = 0)
# void QStatusBar::removeWidget(QWidget * widget)

    @pyqtSlot()
    def on_run_script(self):
        files = os.listdir('scripts')
        files.sort()
        script_files = [fn for fn in files if fn[0] != '.' and fn.endswith('.py')]
        # print(script_files)
        menu = QMenu(self)
        for script_filename in script_files:
            act = QAction(menu)
            act.setText('Run "scripts/' + script_filename + '"...')
            act.setData('scripts/' + script_filename)
            menu.addAction(act)
        act_ret = menu.exec(QCursor.pos())
        if act_ret is None:
            return
        script_filename = str(act_ret.data())
        s = ''
        try:
            with open(script_filename, 'rt', encoding='utf-8') as f:
                s = f.read()
        except IOError:
            pass
        if s != '':
            exec(s)
Ejemplo n.º 37
0
class TVLinker(QWidget):
    def __init__(self, settings: QSettings, parent=None):
        super(TVLinker, self).__init__(parent)
        self.firstrun = True
        self.rows, self.cols = 0, 0
        self.parent = parent
        self.settings = settings
        self.taskbar = TaskbarProgress(self)
        self.init_styles()
        self.init_settings()
        self.init_icons()
        if sys.platform.startswith('linux'):
            notify.init(qApp.applicationName())
        layout = QVBoxLayout()
        layout.setSpacing(0)
        layout.setContentsMargins(15, 15, 15, 0)
        form_groupbox = QGroupBox(self, objectName='mainForm')
        form_groupbox.setLayout(self.init_form())
        self.table = TVLinkerTable(0, 4, self)
        self.table.doubleClicked.connect(self.show_hosters)
        layout.addWidget(form_groupbox)
        layout.addWidget(self.table)
        layout.addLayout(self.init_metabar())
        self.setLayout(layout)
        qApp.setWindowIcon(self.icon_app)
        self.resize(FixedSettings.windowSize)
        self.show()
        self.start_scraping()
        self.firstrun = False

    class ProcError(Enum):
        FAILED_TO_START = 0
        CRASHED = 1
        TIMED_OUT = 2
        READ_ERROR = 3
        WRITE_ERROR = 4
        UNKNOWN_ERROR = 5

    class NotifyIcon(Enum):
        SUCCESS = ':assets/images/tvlinker.png'
        DEFAULT = ':assets/images/tvlinker.png'

    def init_threads(self, threadtype: str = 'scrape') -> None:
        if threadtype == 'scrape':
            if hasattr(self, 'scrapeThread'):
                if not sip.isdeleted(
                        self.scrapeThread) and self.scrapeThread.isRunning():
                    self.scrapeThread.terminate()
                    del self.scrapeWorker
                    del self.scrapeThread
            self.scrapeThread = QThread(self)
            self.scrapeWorker = ScrapeWorker(self.source_url, self.user_agent,
                                             self.dl_pagecount)
            self.scrapeThread.started.connect(self.show_progress)
            self.scrapeThread.started.connect(self.scrapeWorker.begin)
            self.scrapeWorker.moveToThread(self.scrapeThread)
            self.scrapeWorker.addRow.connect(self.add_row)
            self.scrapeWorker.workFinished.connect(self.scrape_finished)
            self.scrapeWorker.workFinished.connect(
                self.scrapeWorker.deleteLater, Qt.DirectConnection)
            self.scrapeWorker.workFinished.connect(self.scrapeThread.quit,
                                                   Qt.DirectConnection)
            self.scrapeThread.finished.connect(self.scrapeThread.deleteLater,
                                               Qt.DirectConnection)
        elif threadtype == 'unrestrict':
            pass

    @staticmethod
    def load_stylesheet(qssfile: str) -> None:
        if QFileInfo(qssfile).exists():
            qss = QFile(qssfile)
            qss.open(QFile.ReadOnly | QFile.Text)
            qApp.setStyleSheet(QTextStream(qss).readAll())

    def init_styles(self) -> None:
        if sys.platform == 'darwin':
            qss_stylesheet = self.get_path('%s_osx.qss' %
                                           qApp.applicationName().lower())
        else:
            qss_stylesheet = self.get_path('%s.qss' %
                                           qApp.applicationName().lower())
        TVLinker.load_stylesheet(qss_stylesheet)
        QFontDatabase.addApplicationFont(':assets/fonts/opensans.ttf')
        QFontDatabase.addApplicationFont(':assets/fonts/opensans-bold.ttf')
        QFontDatabase.addApplicationFont(':assets/fonts/opensans-semibold.ttf')
        qApp.setFont(QFont('Open Sans',
                           12 if sys.platform == 'darwin' else 10))

    def init_icons(self) -> None:
        self.icon_app = QIcon(
            self.get_path('images/%s.png' % qApp.applicationName().lower()))
        self.icon_faves_off = QIcon(':assets/images/star_off.png')
        self.icon_faves_on = QIcon(':assets/images/star_on.png')
        self.icon_refresh = QIcon(':assets/images/refresh.png')
        self.icon_menu = QIcon(':assets/images/menu.png')
        self.icon_settings = QIcon(':assets/images/cog.png')
        self.icon_updates = QIcon(':assets/images/cloud.png')

    def init_settings(self) -> None:
        self.provider = 'Scene-RLS'
        self.select_provider(0)
        self.user_agent = self.settings.value('user_agent')
        self.dl_pagecount = self.settings.value('dl_pagecount', 20, int)
        self.dl_pagelinks = FixedSettings.linksPerPage
        self.realdebrid_api_token = self.settings.value('realdebrid_apitoken')
        self.realdebrid_api_proxy = self.settings.value('realdebrid_apiproxy')
        self.download_manager = self.settings.value('download_manager')
        self.persepolis_cmd = self.settings.value('persepolis_cmd')
        self.pyload_host = self.settings.value('pyload_host')
        self.pyload_username = self.settings.value('pyload_username')
        self.pyload_password = self.settings.value('pyload_password')
        self.idm_exe_path = self.settings.value('idm_exe_path')
        self.kget_cmd = self.settings.value('kget_cmd')
        self.favorites = self.settings.value('favorites')

    def init_form(self) -> QHBoxLayout:
        self.search_field = QLineEdit(self,
                                      clearButtonEnabled=True,
                                      placeholderText='Enter search criteria')
        self.search_field.setObjectName('searchInput')
        self.search_field.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Fixed)
        self.search_field.setFocus()
        self.search_field.textChanged.connect(self.clear_filters)
        self.search_field.returnPressed.connect(
            lambda: self.filter_table(self.search_field.text()))
        self.favorites_button = QPushButton(parent=self,
                                            flat=True,
                                            cursor=Qt.PointingHandCursor,
                                            objectName='favesButton',
                                            toolTip='Favorites',
                                            checkable=True,
                                            toggled=self.filter_faves,
                                            checked=self.settings.value(
                                                'faves_filter', False, bool))
        self.refresh_button = QPushButton(parent=self,
                                          flat=True,
                                          cursor=Qt.PointingHandCursor,
                                          objectName='refreshButton',
                                          toolTip='Refresh',
                                          clicked=self.start_scraping)
        self.dlpages_field = QComboBox(self,
                                       toolTip='Pages',
                                       editable=False,
                                       cursor=Qt.PointingHandCursor)
        self.dlpages_field.addItems(
            ('10', '20', '30', '40', '50', '60', '70', '80'))
        self.dlpages_field.setCurrentIndex(
            self.dlpages_field.findText(str(self.dl_pagecount),
                                        Qt.MatchFixedString))
        self.dlpages_field.currentIndexChanged.connect(self.update_pagecount)
        self.settings_button = QPushButton(parent=self,
                                           flat=True,
                                           toolTip='Menu',
                                           objectName='menuButton',
                                           cursor=Qt.PointingHandCursor)
        self.settings_button.setMenu(self.settings_menu())
        layout = QHBoxLayout(spacing=10)
        # providerCombo = QComboBox(self, toolTip='Provider', editable=False, cursor=Qt.PointingHandCursor)
        # providerCombo.setObjectName('providercombo')
        # providerCombo.addItem(QIcon(':assets/images/provider-scenerls.png'), '')
        # providerCombo.addItem(QIcon(':assets/images/provider-tvrelease.png'), '')
        # providerCombo.setIconSize(QSize(146, 36))
        # providerCombo.setMinimumSize(QSize(160, 40))
        # providerCombo.setStyleSheet('''
        #     QComboBox, QComboBox::drop-down { background-color: transparent; border: none; margin: 5px; }
        #     QComboBox::down-arrow { image: url(:assets/images/down_arrow.png); }
        #     QComboBox QAbstractItemView { selection-background-color: #DDDDE4; }
        # ''')
        # providerCombo.currentIndexChanged.connect(self.select_provider)
        layout.addWidget(
            QLabel(pixmap=QPixmap(':assets/images/provider-scenerls.png')))
        layout.addWidget(self.search_field)
        layout.addWidget(self.favorites_button)
        layout.addWidget(self.refresh_button)
        layout.addWidget(QLabel('Pages:'))
        layout.addWidget(self.dlpages_field)
        layout.addWidget(self.settings_button)
        return layout

    @pyqtSlot(int)
    def select_provider(self, index: int):
        if index == 0:
            self.provider = 'Scene-RLS'
            self.source_url = 'http://scene-rls.net/releases/index.php?p={0}&cat=TV%20Shows'
        elif index == 1:
            self.provider = 'TV-Release'
            self.source_url = 'http://tv-release.pw/?cat=TV'
        self.setWindowTitle('%s :: %s' %
                            (qApp.applicationName(), self.provider))

    def settings_menu(self) -> QMenu:
        settings_action = QAction(self.icon_settings,
                                  'Settings',
                                  self,
                                  triggered=self.show_settings)
        updates_action = QAction(self.icon_updates,
                                 'Check for updates',
                                 self,
                                 triggered=self.check_update)
        aboutqt_action = QAction('About Qt', self, triggered=qApp.aboutQt)
        about_action = QAction('About %s' % qApp.applicationName(),
                               self,
                               triggered=self.about_app)
        menu = QMenu()
        menu.addAction(settings_action)
        menu.addAction(updates_action)
        menu.addSeparator()
        menu.addAction(aboutqt_action)
        menu.addAction(about_action)
        return menu

    def init_metabar(self) -> QHBoxLayout:
        self.meta_template = 'Total number of links retrieved: <b>%i</b> / <b>%i</b>'
        self.progress = QProgressBar(parent=self,
                                     minimum=0,
                                     maximum=(self.dl_pagecount *
                                              self.dl_pagelinks),
                                     visible=False)
        self.taskbar.setProgress(0.0, True)
        if sys.platform == 'win32':
            self.win_taskbar_button = QWinTaskbarButton(self)

        self.meta_label = QLabel(textFormat=Qt.RichText,
                                 alignment=Qt.AlignRight,
                                 objectName='totals')
        self.update_metabar()
        layout = QHBoxLayout()
        layout.setContentsMargins(10, 5, 10, 10)
        layout.addWidget(self.progress, Qt.AlignLeft)
        layout.addWidget(self.meta_label, Qt.AlignRight)
        return layout

    @pyqtSlot()
    def check_update(self) -> None:
        QDesktopServices.openUrl(QUrl(FixedSettings.latest_release_url))

    @pyqtSlot()
    def show_settings(self) -> None:
        settings_win = Settings(self, self.settings)
        settings_win.exec_()

    def update_metabar(self) -> bool:
        rowcount = self.table.rowCount()
        self.meta_label.setText(
            self.meta_template %
            (rowcount, self.dl_pagecount * self.dl_pagelinks))
        self.progress.setValue(rowcount)
        self.taskbar.setProgress(rowcount / self.progress.maximum())
        if sys.platform == 'win32':
            self.win_taskbar_button.progress().setValue(self.progress.value())
        return True

    def start_scraping(self) -> None:
        self.init_threads('scrape')
        self.rows = 0
        self.table.clearContents()
        self.table.setRowCount(0)
        self.table.setSortingEnabled(False)
        self.update_metabar()
        self.scrapeThread.start()

    @pyqtSlot()
    def about_app(self) -> None:
        about_html = '''<style>
        a { color:#441d4e; text-decoration:none; font-weight:bold; }
        a:hover { text-decoration:underline; }
    </style>
    <p style="font-size:24pt; font-weight:bold; color:#6A687D;">%s</p>
    <p>
        <span style="font-size:13pt;"><b>Version: %s</b></span>
        <span style="font-size:10pt;position:relative;left:5px;">( %s )</span>
    </p>
    <p style="font-size:13px;">
        Copyright &copy; %s <a href="mailto:[email protected]">Pete Alexandrou</a>
        <br/>
        Web: <a href="%s">%s</a>
    </p>
    <p style="font-size:11px;">
        This program is free software; you can redistribute it and/or
        modify it under the terms of the GNU General Public License
        as published by the Free Software Foundation; either version 2
        of the License, or (at your option) any later version.
    </p>''' % (qApp.applicationName(), qApp.applicationVersion(),
               platform.architecture()[0], datetime.now().year,
               qApp.organizationDomain(), qApp.organizationDomain())
        QMessageBox.about(self, 'About %s' % qApp.applicationName(),
                          about_html)

    @pyqtSlot(int)
    def update_pagecount(self, index: int) -> None:
        self.dl_pagecount = int(self.dlpages_field.itemText(index))
        self.scrapeWorker.maxpages = self.dl_pagecount
        self.progress.setMaximum(self.dl_pagecount * self.dl_pagelinks)
        self.settings.setValue('dl_pagecount', self.dl_pagecount)
        if sys.platform == 'win32':
            self.win_taskbar_button.progress().setMaximum(self.dl_pagecount *
                                                          self.dl_pagelinks)
        if self.scrapeThread.isRunning():
            self.scrapeThread.requestInterruption()
        self.start_scraping()

    @pyqtSlot()
    def show_progress(self):
        self.progress.show()
        self.taskbar.setProgress(0.0, True)
        if sys.platform == 'win32':
            self.win_taskbar_button.setWindow(self.windowHandle())
            self.win_taskbar_button.progress().setRange(
                0, self.dl_pagecount * self.dl_pagelinks)
            self.win_taskbar_button.progress().setVisible(True)
            self.win_taskbar_button.progress().setValue(self.progress.value())

    @pyqtSlot()
    def scrape_finished(self) -> None:
        self.progress.hide()
        self.taskbar.setProgress(0.0, False)
        if sys.platform == 'win32':
            self.win_taskbar_button.progress().setVisible(False)
        self.table.setSortingEnabled(True)
        self.filter_table(text='')

    @pyqtSlot(list)
    def add_row(self, row: list) -> None:
        if self.scrapeThread.isInterruptionRequested():
            self.scrapeThread.terminate()
        else:
            self.cols = 0
            self.table.setRowCount(self.rows + 1)
            if self.table.cursor() != Qt.PointingHandCursor:
                self.table.setCursor(Qt.PointingHandCursor)
            for item in row:
                table_item = QTableWidgetItem(item)
                table_item.setToolTip(
                    '%s\n\nDouble-click to view hoster links.' % row[1])
                table_item.setFont(QFont('Open Sans', weight=QFont.Normal))
                if self.cols == 2:
                    if sys.platform == 'win32':
                        table_item.setFont(
                            QFont('Open Sans Semibold', pointSize=10))
                    elif sys.platform == 'darwin':
                        table_item.setFont(
                            QFont('Open Sans Bold', weight=QFont.Bold))
                    else:
                        table_item.setFont(
                            QFont('Open Sans',
                                  weight=QFont.DemiBold,
                                  pointSize=10))
                    table_item.setText('  ' + table_item.text())
                elif self.cols in (0, 3):
                    table_item.setTextAlignment(Qt.AlignCenter)
                self.table.setItem(self.rows, self.cols, table_item)
                self.update_metabar()
                self.cols += 1
            self.rows += 1

    @pyqtSlot(list)
    def add_hosters(self, links: list) -> None:
        self.hosters_win.show_hosters(links)

    @pyqtSlot(QModelIndex)
    def show_hosters(self, index: QModelIndex) -> None:
        qApp.setOverrideCursor(Qt.BusyCursor)
        self.hosters_win = HosterLinks(self)
        self.hosters_win.downloadLink.connect(self.download_link)
        self.hosters_win.copyLink.connect(self.copy_download_link)
        self.links = HostersThread(
            self.table.item(self.table.currentRow(), 1).text(),
            self.user_agent)
        self.links.setHosters.connect(self.add_hosters)
        self.links.noLinks.connect(self.no_links)
        self.links.start()

    @pyqtSlot()
    def no_links(self) -> None:
        self.hosters_win.loading_progress.cancel()
        self.hosters_win.close()
        QMessageBox.warning(
            self, 'No Links Available',
            'No links are available yet for the chosen TV show. ' +
            'This is most likely due to the files still being uploaded. This is normal if the '
            +
            'link was published 30-45 mins ago.\n\nPlease check back again in 10-15 minutes.'
        )

    @pyqtSlot(bool)
    def filter_faves(self, checked: bool) -> None:
        self.settings.setValue('faves_filter', checked)
        # if hasattr(self, 'scrapeWorker') and (sip.isdeleted(self.scrapeWorker) or self.scrapeWorker.complete):
        if not self.firstrun:
            self.filter_table()

    @pyqtSlot(str)
    @pyqtSlot()
    def filter_table(self, text: str = '') -> None:
        filters = []
        if self.favorites_button.isChecked():
            filters = self.favorites
            self.table.sortItems(2, Qt.AscendingOrder)
        else:
            self.table.sortItems(0, Qt.DescendingOrder)
        if len(text):
            filters.append(text)
        if not len(filters) or not hasattr(self, 'valid_rows'):
            self.valid_rows = []
        for search_term in filters:
            for item in self.table.findItems(search_term, Qt.MatchContains):
                self.valid_rows.append(item.row())
        for row in range(0, self.table.rowCount()):
            if not len(filters):
                self.table.showRow(row)
            else:
                if row not in self.valid_rows:
                    self.table.hideRow(row)
                else:
                    self.table.showRow(row)

    @pyqtSlot()
    def clear_filters(self):
        if not len(self.search_field.text()):
            self.filter_table('')

    @pyqtSlot(bool)
    def aria2_confirmation(self, success: bool) -> None:
        qApp.restoreOverrideCursor()
        if success:
            if sys.platform.startswith('linux'):
                self.notify(
                    title=qApp.applicationName(),
                    msg='Your download link has been unrestricted and now ' +
                    'queued in Aria2 RPC Daemon',
                    icon=self.NotifyIcon.SUCCESS)
            else:
                QMessageBox.information(
                    self, qApp.applicationName(),
                    'Download link has been queued in Aria2.', QMessageBox.Ok)
        else:
            QMessageBox.critical(
                self, 'Aria2 RPC Daemon',
                'Could not connect to Aria2 RPC Daemon. ' +
                'Check your %s settings and try again.' %
                qApp.applicationName(), QMessageBox.Ok)

    @pyqtSlot(str)
    def download_link(self, link: str) -> None:
        if len(self.realdebrid_api_token) > 0 and 'real-debrid.com' not in link \
            and 'rdeb.io' not in link:
            qApp.setOverrideCursor(Qt.BusyCursor)
            self.unrestrict_link(link, True)
        else:
            if self.download_manager == 'aria2':
                self.aria2 = Aria2Thread(settings=self.settings, link_url=link)
                self.aria2.aria2Confirmation.connect(self.aria2_confirmation)
                self.aria2.start()
                self.hosters_win.close()
            elif self.download_manager == 'pyload':
                self.pyload_conn = PyloadConnection(self.pyload_host,
                                                    self.pyload_username,
                                                    self.pyload_password)
                pid = self.pyload_conn.addPackage(name='TVLinker',
                                                  links=[link])
                qApp.restoreOverrideCursor()
                self.hosters_win.close()
                if sys.platform.startswith('linux'):
                    self.notify(title='Download added to %s' %
                                self.download_manager,
                                icon=self.NotifyIcon.SUCCESS)
                else:
                    QMessageBox.information(
                        self, self.download_manager,
                        'Your link has been queued in %s.' %
                        self.download_manager, QMessageBox.Ok)
                # open_pyload = msgbox.addButton('Open pyLoad', QMessageBox.AcceptRole)
                # open_pyload.clicked.connect(self.open_pyload)
            elif self.download_manager in ('kget', 'persepolis'):
                provider = self.kget_cmd if self.download_manager == 'kget' else self.persepolis_cmd
                cmd = '{0} "{1}"'.format(provider, link)
                if self.cmdexec(cmd):
                    qApp.restoreOverrideCursor()
                    self.hosters_win.close()
                    if sys.platform.startswith('linux'):
                        self.notify(title='Download added to %s' %
                                    self.download_manager,
                                    icon=self.NotifyIcon.SUCCESS)
                    else:
                        QMessageBox.information(
                            self, self.download_manager,
                            'Your link has been queued in %s.' %
                            self.download_manager, QMessageBox.Ok)
            elif self.download_manager == 'idm':
                cmd = '"%s" /n /d "%s"' % (self.idm_exe_path, link)
                if self.cmdexec(cmd):
                    qApp.restoreOverrideCursor()
                    self.hosters_win.close()
                    QMessageBox.information(
                        self, 'Internet Download Manager',
                        'Your link has been queued in IDM.')
                else:
                    print('IDM QProcess error = %s' %
                          self.ProcError(self.idm.error()).name)
                    qApp.restoreOverrideCursor()
                    self.hosters_win.close()
                    QMessageBox.critical(
                        self, 'Internet Download Manager',
                        '<p>Could not connect to your local IDM application instance. '
                        +
                        'Please check your settings and ensure the IDM executable path is correct '
                        +
                        'according to your installation.</p><p>Error Code: %s</p>'
                        % self.ProcError(self.idm.error()).name,
                        QMessageBox.Ok)
            else:
                dlpath, _ = QFileDialog.getSaveFileName(
                    self, 'Save File',
                    link.split('/')[-1])
                if dlpath != '':
                    self.directdl_win = DirectDownload(parent=self)
                    self.directdl = DownloadThread(link_url=link,
                                                   dl_path=dlpath)
                    self.directdl.dlComplete.connect(
                        self.directdl_win.download_complete)
                    if sys.platform.startswith('linux'):
                        self.directdl.dlComplete.connect(
                            lambda: self.notify(qApp.applicationName(
                            ), 'Download complete', self.NotifyIcon.SUCCESS))
                    else:
                        self.directdl.dlComplete.connect(
                            lambda: QMessageBox.information(
                                self, qApp.applicationName(),
                                'Download complete', QMessageBox.Ok))
                    self.directdl.dlProgressTxt.connect(
                        self.directdl_win.update_progress_label)
                    self.directdl.dlProgress.connect(
                        self.directdl_win.update_progress)
                    self.directdl_win.cancelDownload.connect(
                        self.cancel_download)
                    self.directdl.start()
                    self.hosters_win.close()

    def _init_notification_icons(self):
        for icon in self.NotifyIcon:
            icon_file = QPixmap(icon.value, 'PNG')
            icon_file.save(
                os.path.join(FixedSettings.config_path,
                             os.path.basename(icon.value)), 'PNG', 100)

    def notify(self,
               title: str,
               msg: str = '',
               icon: Enum = None,
               urgency: int = 1) -> bool:
        icon_path = icon.value if icon is not None else self.NotifyIcon.DEFAULT.value
        icon_path = os.path.join(FixedSettings.config_path,
                                 os.path.basename(icon_path))
        if not os.path.exists(icon_path):
            self._init_notification_icons()
        notification = notify.Notification(title, msg, icon_path)
        notification.set_urgency(urgency)
        return notification.show()

    def cmdexec(self, cmd: str) -> bool:
        self.proc = QProcess()
        self.proc.setProcessChannelMode(QProcess.MergedChannels)
        if hasattr(self.proc, 'errorOccurred'):
            self.proc.errorOccurred.connect(lambda error: print(
                'Process error = %s' % self.ProcError(error).name))
        if self.proc.state() == QProcess.NotRunning:
            self.proc.start(cmd)
            self.proc.waitForFinished(-1)
            rc = self.proc.exitStatus(
            ) == QProcess.NormalExit and self.proc.exitCode() == 0
            self.proc.deleteLater()
            return rc
        return False

    @pyqtSlot()
    def cancel_download(self) -> None:
        self.directdl.cancel_download = True
        self.directdl.quit()
        self.directdl.deleteLater()

    def open_pyload(self) -> None:
        QDesktopServices.openUrl(QUrl(self.pyload_config.host))

    @pyqtSlot(str)
    def copy_download_link(self, link: str) -> None:
        if len(self.realdebrid_api_token) > 0 and 'real-debrid.com' not in link \
            and 'rdeb.io' not in link:
            qApp.setOverrideCursor(Qt.BusyCursor)
            self.unrestrict_link(link, False)
        else:
            clip = qApp.clipboard()
            clip.setText(link)
            self.hosters_win.close()
            qApp.restoreOverrideCursor()

    def unrestrict_link(self, link: str, download: bool = True) -> None:
        caller = inspect.stack()[1].function
        self.realdebrid = RealDebridThread(
            settings=self.settings,
            api_url=FixedSettings.realdebrid_api_url,
            link_url=link,
            action=RealDebridThread.RealDebridAction.UNRESTRICT_LINK)
        self.realdebrid.errorMsg.connect(self.error_handler)
        if download:
            self.realdebrid.unrestrictedLink.connect(self.download_link)
        else:
            self.realdebrid.unrestrictedLink.connect(self.copy_download_link)
        self.realdebrid.start()

    def closeEvent(self, event: QCloseEvent) -> None:
        if hasattr(self, 'scrapeThread'):
            if not sip.isdeleted(
                    self.scrapeThread) and self.scrapeThread.isRunning():
                self.scrapeThread.requestInterruption()
                self.scrapeThread.quit()
        qApp.quit()

    def error_handler(self, props: list) -> None:
        qApp.restoreOverrideCursor()
        QMessageBox.critical(self, props[0], props[1], QMessageBox.Ok)

    @staticmethod
    def get_path(path: str = None, override: bool = False) -> str:
        if override:
            if getattr(sys, 'frozen', False):
                return os.path.join(sys._MEIPASS, path)
            return os.path.join(QFileInfo(__file__).absolutePath(), path)
        return ':assets/%s' % path

    @staticmethod
    def get_version(filename: str = '__init__.py') -> str:
        with open(TVLinker.get_path(filename, override=True), 'r') as initfile:
            for line in initfile.readlines():
                m = re.match('__version__ *= *[\'](.*)[\']', line)
                if m:
                    return m.group(1)
Ejemplo n.º 38
0
class UpdateCheck(QWidget, Logger):
    url = "https://raw.githubusercontent.com/axerunners/electrum-axe/master/.latest-version"
    download_url = "https://github.com/axerunners/electrum-axe/releases"


    VERSION_ANNOUNCEMENT_SIGNING_KEYS = (
        "XuKFPN7RDbrvNsPddPyUPzVqwdhvfB67cx",
    )

    def __init__(self, main_window, latest_version=None):
        self.main_window = main_window
        QWidget.__init__(self)
        self.setWindowTitle('Axe Electrum - ' + _('Update Check'))
        self.content = QVBoxLayout()
        self.content.setContentsMargins(*[10]*4)

        self.heading_label = QLabel()
        self.content.addWidget(self.heading_label)

        self.detail_label = QLabel()
        self.detail_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
        self.detail_label.setOpenExternalLinks(True)
        self.content.addWidget(self.detail_label)

        self.pb = QProgressBar()
        self.pb.setMaximum(0)
        self.pb.setMinimum(0)
        self.content.addWidget(self.pb)

        versions = QHBoxLayout()
        versions.addWidget(QLabel(_("Current version: {}".format(version.ELECTRUM_VERSION))))
        self.latest_version_label = QLabel(_("Latest version: {}".format(" ")))
        versions.addWidget(self.latest_version_label)
        self.content.addLayout(versions)

        self.update_view(latest_version)

        self.update_check_thread = UpdateCheckThread(self.main_window)
        self.update_check_thread.checked.connect(self.on_version_retrieved)
        self.update_check_thread.failed.connect(self.on_retrieval_failed)
        self.update_check_thread.start()

        close_button = QPushButton(_("Close"))
        close_button.clicked.connect(self.close)
        self.content.addWidget(close_button)
        self.setLayout(self.content)
        self.show()

    def on_version_retrieved(self, version):
        self.update_view(version)

    def on_retrieval_failed(self):
        self.heading_label.setText('<h2>' + _("Update check failed") + '</h2>')
        self.detail_label.setText(_("Sorry, but we were unable to check for updates. Please try again later."))
        self.pb.hide()

    @staticmethod
    def is_newer(latest_version):
        v = version.ELECTRUM_VERSION
        if 'rc' in v:
            v = v[:v.index('rc')]
        if 'rc' in latest_version:
            latest_version = latest_version[:latest_version.index('rc')]
        return versiontuple(latest_version) > versiontuple(v)

    def update_view(self, latest_version=None):
        if latest_version:
            self.pb.hide()
            self.latest_version_label.setText(_("Latest version: {}".format(latest_version)))
            if self.is_newer(latest_version):
                self.heading_label.setText('<h2>' + _("There is a new update available") + '</h2>')
                url = "<a href='{u}'>{u}</a>".format(u=UpdateCheck.download_url)
                self.detail_label.setText(_("You can download the new version from {}.").format(url))
            else:
                self.heading_label.setText('<h2>' + _("Already up to date") + '</h2>')
                self.detail_label.setText(_("You are already on the latest version of Axe Electrum."))
        else:
            self.heading_label.setText('<h2>' + _("Checking for updates...") + '</h2>')
            self.detail_label.setText(_("Please wait while Axe Electrum checks for available updates."))
Ejemplo n.º 39
0
class TaggerDialog(QDialog):
    def __init__(self, args, **kwargs):
        super(TaggerDialog, self).__init__(**kwargs)

        self.reviewing = False
        self.args = args

        self.worker = TaggerWorker()
        self.thread = QThread()
        self.worker.moveToThread(self.thread)

        self.worker.on_error.connect(self.on_error)
        self.worker.on_review_ready.connect(self.on_review_ready)
        self.worker.on_stopped.connect(self.on_stopped)
        self.worker.on_progress.connect(self.on_progress)
        self.worker.on_updates_sent.connect(self.on_updates_sent)
        self.worker.on_mint_mfa.connect(self.on_mint_mfa)

        self.thread.started.connect(
            partial(self.worker.create_updates, args, self))
        self.thread.start()

        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('Tagger is running...')
        self.setModal(True)
        self.v_layout = QVBoxLayout()
        self.setLayout(self.v_layout)

        self.label = QLabel()
        self.v_layout.addWidget(self.label)

        self.progress = 0
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 0)
        self.v_layout.addWidget(self.progress_bar)

        self.button_bar = QHBoxLayout()
        self.v_layout.addLayout(self.button_bar)

        self.cancel_button = QPushButton('Cancel')
        self.button_bar.addWidget(self.cancel_button)
        self.cancel_button.clicked.connect(self.on_cancel)

    def on_error(self, msg):
        logger.error(msg)
        self.label.setText('Error: {}'.format(msg))
        self.label.setStyleSheet('QLabel { color: red; font-weight: bold; }')
        self.cancel_button.setText('Close')
        self.cancel_button.clicked.connect(self.close)

    def open_amazon_order_id(self, order_id):
        if order_id:
            QDesktopServices.openUrl(QUrl(amazon.get_invoice_url(order_id)))

    def on_activated(self, index):
        # Only handle clicks on the order_id cell.
        if index.column() != 5:
            return
        order_id = self.updates_table_model.data(index, Qt.DisplayRole)
        self.open_amazon_order_id(order_id)

    def on_double_click(self, index):
        if index.column() == 5:
            # Ignore double clicks on the order_id cell.
            return
        order_id_cell = self.updates_table_model.createIndex(index.row(), 5)
        order_id = self.updates_table_model.data(order_id_cell, Qt.DisplayRole)
        self.open_amazon_order_id(order_id)

    def on_review_ready(self, results):
        self.reviewing = True
        self.progress_bar.hide()

        self.label.setText('Select below which updates to send to Mint.')

        self.updates_table_model = MintUpdatesTableModel(results.updates)
        self.updates_table = QTableView()
        self.updates_table.doubleClicked.connect(self.on_double_click)
        self.updates_table.clicked.connect(self.on_activated)

        def resize():
            self.updates_table.resizeColumnsToContents()
            self.updates_table.resizeRowsToContents()
            min_width = sum(
                self.updates_table.columnWidth(i) for i in range(6))
            self.updates_table.setMinimumSize(min_width + 20, 600)

        self.updates_table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.updates_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.updates_table.setModel(self.updates_table_model)
        self.updates_table.setSortingEnabled(True)
        resize()
        self.updates_table_model.layoutChanged.connect(resize)

        self.v_layout.insertWidget(2, self.updates_table)

        unmatched_button = QPushButton('View Unmatched Amazon orders')
        self.button_bar.addWidget(unmatched_button)
        unmatched_button.clicked.connect(
            partial(self.on_open_unmatched, results.unmatched_orders))

        amazon_stats_button = QPushButton('Amazon Stats')
        self.button_bar.addWidget(amazon_stats_button)
        amazon_stats_button.clicked.connect(
            partial(self.on_open_amazon_stats, results.items, results.orders,
                    results.refunds))

        tagger_stats_button = QPushButton('Tagger Stats')
        self.button_bar.addWidget(tagger_stats_button)
        tagger_stats_button.clicked.connect(
            partial(self.on_open_tagger_stats, results.stats))

        self.confirm_button = QPushButton('Send to Mint')
        self.button_bar.addWidget(self.confirm_button)
        self.confirm_button.clicked.connect(self.on_send)

        self.setGeometry(50, 50, self.width(), self.height())

    def on_updates_sent(self, num_sent):
        self.label.setText(
            'All done! {} newly tagged Mint transactions'.format(num_sent))
        self.cancel_button.setText('Close')

    def on_open_unmatched(self, unmatched):
        self.unmatched_dialog = AmazonUnmatchedTableDialog(unmatched)
        self.unmatched_dialog.show()

    def on_open_amazon_stats(self, items, orders, refunds):
        self.amazon_stats_dialog = AmazonStatsDialog(items, orders, refunds)
        self.amazon_stats_dialog.show()

    def on_open_tagger_stats(self, stats):
        self.tagger_stats_dialog = TaggerStatsDialog(stats)
        self.tagger_stats_dialog.show()

    def on_send(self):
        self.progress_bar.show()
        updates = self.updates_table_model.get_selected_updates()

        self.confirm_button.hide()
        self.updates_table.hide()
        self.confirm_button.deleteLater()
        self.updates_table.deleteLater()
        self.adjustSize()

        QMetaObject.invokeMethod(self.worker, 'send_updates',
                                 Qt.QueuedConnection, Q_ARG(list, updates),
                                 Q_ARG(object, self.args))

    def on_stopped(self):
        self.close()

    def on_progress(self, msg, max, value):
        self.label.setText(msg)
        self.progress_bar.setRange(0, max)
        self.progress_bar.setValue(value)

    def on_cancel(self):
        if not self.reviewing:
            QMetaObject.invokeMethod(self.worker, 'stop', Qt.QueuedConnection)
        else:
            self.close()

    def on_mint_mfa(self):
        mfa_code, ok = QInputDialog().getText(self,
                                              'Please enter your Mint Code.',
                                              'Mint Code:')
        self.worker.mfa_code = mfa_code
        QMetaObject.invokeMethod(self.worker, 'mfa_code', Qt.QueuedConnection,
                                 Q_ARG(str, mfa_code))
        self.worker.on_mint_mfa_done.emit()
Ejemplo n.º 40
0
class FingerPrintManager(QWidget):
    def __init__(self, djv):
        super().__init__()
        self.djv = djv
        self.initUI()

    def initUI(self):
        songs = [s['song_name'] for s in self.djv.db.get_songs()]
        songs_list = QListWidget(self)
        songs_list.setFixedSize(800, 400)
        for s in songs:
            songs_list.addItem(s)

        self.button = QPushButton("New song")
        self.button.setToolTip('Click here to fingerprint a new song.')
        self.button.clicked.connect(self.open_file)

        self.progress = QProgressBar()
        self.progress.setFixedSize(800, 30)

        self.v1 = QVBoxLayout(self)
        self.v1.setAlignment(Qt.AlignHCenter)
        self.v1.addStretch()
        self.v1.addWidget(songs_list)
        self.v1.addStretch()
        self.v1.addWidget(self.button)
        self.v1.addStretch()
        self.v1.addWidget(self.progress)
        self.v1.addStretch()

        self.progress.hide()

        self.setWindowTitle("Fingerprints Manager")
        self.setGeometry(500, 500, 1100, 550)
        self.setFixedSize(1100, 550)

    def open_file(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "QFileDialog.getOpenFileNames()",
            "",
            "All Files (*);;MP3 Files (*.mp3)",
            options=options)

        self.fingerprint(files)

    def fingerprint(self, files):
        if len(files) == 0:
            return "Empty"

        print("Start fingerprinting {}".format(files))
        self.button.setDisabled(True)

        self.progress.setMaximum(len(files))
        self.progress.setValue(0)
        self.progress.show()

        self.prog = FingerprintThread(self.djv, files)
        self.prog.countChanged.connect(self.on_count_change)
        self.prog.start()

    def on_count_change(self, value, max_value):
        if value < max_value:
            self.progress.setValue(value)
        else:
            self.button.setDisabled(False)
            self.progress.hide()
Ejemplo n.º 41
0
class CueWidget(QWidget):

    STOP = QIcon.fromTheme('led-off')
    START = QIcon.fromTheme('led-running')
    PAUSE = QIcon.fromTheme('led-pause')
    ERROR = QIcon.fromTheme('led-error')

    ICON_SIZE = 14

    context_menu_request = pyqtSignal(object, QPoint)
    edit_request = pyqtSignal(object)
    cue_executed = pyqtSignal(object)

    def __init__(self, cue, **kwargs):
        super().__init__(**kwargs)
        self.cue = None

        self._selected = False
        self._accurate_timing = False
        self._show_dbmeter = False
        self._countdown_mode = True

        self._dbmeter_element = None
        self._fade_element = None

        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setLayout(QGridLayout())

        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().setSpacing(2)
        self.layout().setColumnStretch(0, 6)
        self.layout().setRowStretch(0, 4)

        self.nameButton = QClickLabel(self)
        self.nameButton.setObjectName('ButtonCueWidget')
        self.nameButton.setWordWrap(True)
        self.nameButton.setAlignment(Qt.AlignCenter)
        self.nameButton.setFocusPolicy(Qt.NoFocus)
        self.nameButton.clicked.connect(self._clicked)
        self.nameButton.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.layout().addWidget(self.nameButton, 0, 0)

        self.statusIcon = QLabel(self.nameButton)
        self.statusIcon.setStyleSheet('background-color: transparent')
        self.statusIcon.setPixmap(CueWidget.STOP.pixmap(CueWidget.ICON_SIZE,
                                                        CueWidget.ICON_SIZE))

        self.seekSlider = QClickSlider(self.nameButton)
        self.seekSlider.setOrientation(Qt.Horizontal)
        self.seekSlider.setFocusPolicy(Qt.NoFocus)
        self.seekSlider.setVisible(False)

        self.dbMeter = QDbMeter(self)
        self.dbMeter.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.dbMeter.setVisible(False)

        self.timeBar = QProgressBar(self)
        self.timeBar.setTextVisible(False)
        self.timeBar.setLayout(QHBoxLayout())
        self.timeBar.layout().setContentsMargins(0, 0, 0, 0)
        self.timeDisplay = QLCDNumber(self.timeBar)
        self.timeDisplay.setStyleSheet('background-color: transparent')
        self.timeDisplay.setSegmentStyle(QLCDNumber.Flat)
        self.timeDisplay.setDigitCount(8)
        self.timeDisplay.display('00:00:00')
        self.timeBar.layout().addWidget(self.timeDisplay)
        self.timeBar.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self.timeBar.setVisible(False)

        self._set_cue(cue)

    @property
    def selected(self):
        return self._selected

    @selected.setter
    def selected(self, value):
        self._selected = value
        self._update_style(self.cue.stylesheet)

    def contextMenuEvent(self, event):
        self.context_menu_request.emit(self, event.globalPos())

    def mouseMoveEvent(self, event):
        if (event.buttons() == Qt.LeftButton and
                (event.modifiers() == Qt.ControlModifier or
                 event.modifiers() == Qt.ShiftModifier)):
            mime_data = QMimeData()
            mime_data.setText(PageWidget.DRAG_MAGIC)

            drag = QDrag(self)
            drag.setMimeData(mime_data)
            drag.setPixmap(self.grab(self.rect()))

            if event.modifiers() == Qt.ControlModifier:
                drag.exec_(Qt.MoveAction)
            else:
                drag.exec_(Qt.CopyAction)

            event.accept()
        else:
            event.ignore()

    def set_countdown_mode(self, mode):
        self._countdown_mode = mode
        self._update_time(self.cue.current_time())

    def set_accurate_timing(self, enable):
        self._accurate_timing = enable
        if self.cue.state == CueState.Pause:
            self._update_time(self.cue.current_time(), True)
        elif self.cue.state != CueState.Running:
            self._update_duration(self.cue.duration)

    def show_seek_slider(self, visible):
        self.seekSlider.setVisible(visible)
        self.update()

    def show_dbmeters(self, visible):
        if isinstance(self.cue, MediaCue):
            self._show_dbmeter = visible

            if self._dbmeter_element is not None:
                self._dbmeter_element.level_ready.disconnect(self.dbMeter.plot)
                self._dbmeter_element = None

            if visible:
                self._dbmeter_element = self.cue.media.element('DbMeter')
                if self._dbmeter_element is not None:
                    self._dbmeter_element.level_ready.connect(self.dbMeter.plot)

                self.layout().addWidget(self.dbMeter, 0, 1)
                self.layout().setColumnStretch(1, 1)
                self.dbMeter.show()
            else:
                self.dbMeter.hide()
                self.layout().setColumnStretch(1, 0)

            self.update()

    def _set_cue(self, cue):
        self.cue = cue
        self.cue.changed('name').connect(self._update_name, Connection.QtQueued)
        self.cue.changed('stylesheet').connect(self._update_style, Connection.QtQueued)
        self.cue.changed('duration').connect(self._update_duration, Connection.QtQueued)
        self.cue.changed('description').connect(self._update_description, Connection.QtQueued)

        if isinstance(cue, MediaCue):
            self.cue.media.changed('pipe').connect(self._media_updated)

            self.cue.paused.connect(self.dbMeter.reset, Connection.QtQueued)
            self.cue.stopped.connect(self.dbMeter.reset, Connection.QtQueued)
            self.cue.end.connect(self.dbMeter.reset, Connection.QtQueued)
            self.cue.error.connect(self.dbMeter.reset, Connection.QtQueued)

            self.seekSlider.sliderMoved.connect(self.cue.media.seek)
            self.seekSlider.sliderJumped.connect(self.cue.media.seek)

        # Cue status changed
        self.cue.started.connect(self._status_playing, Connection.QtQueued)
        self.cue.stopped.connect(self._status_stopped, Connection.QtQueued)
        self.cue.paused.connect(self._status_paused, Connection.QtQueued)
        self.cue.error.connect(self._status_error, Connection.QtQueued)
        self.cue.end.connect(self._status_stopped, Connection.QtQueued)

        self._cue_time = CueTime(self.cue)
        self._cue_time.notify.connect(self._update_time)

        self._update_name(cue.name)
        self._update_style(cue.stylesheet)
        self._update_duration(self.cue.duration)

    def _media_updated(self):
        self.show_dbmeters(self._show_dbmeter)

        new_fade = self.cue.media.element('Fade')
        if new_fade is not self._fade_element:
            if self._fade_element is not None:
                self._fade_element.enter_fadein.disconnect(self._enter_fadein)
                self._fade_element.enter_fadeout.disconnect(self._enter_fadeout)
                self._fade_element.exit_fadein.disconnect(self._exit_fade)
                self._fade_element.exit_fadeout.disconnect(self._exit_fade)

            if new_fade is not None:
                self._fade_element = new_fade
                self._fade_element.enter_fadein.connect(self._enter_fadein)
                self._fade_element.enter_fadeout.connect(self._enter_fadeout)
                self._fade_element.exit_fadein.connect(self._exit_fade)
                self._fade_element.exit_fadeout.connect(self._exit_fade)

    def _update_name(self, name):
        self.nameButton.setText(name)

    def _update_description(self, description):
        self.nameButton.setToolTip(description)

    def _clicked(self, event):
        if not self.seekSlider.geometry().contains(event.pos()):
            if event.button() != Qt.RightButton:
                if event.modifiers() == Qt.ShiftModifier:
                    self.edit_request.emit(self.cue)
                elif event.modifiers() == Qt.ControlModifier:
                    self.selected = not self.selected
                else:
                    self.cue_executed.emit(self.cue)
                    self.cue.execute()

    def _update_style(self, stylesheet):
        stylesheet += 'text-decoration: underline;' if self.selected else ''
        self.nameButton.setStyleSheet(stylesheet)

    def _enter_fadein(self):
        p = self.timeDisplay.palette()
        p.setColor(p.WindowText, QColor(0, 255, 0))
        self.timeDisplay.setPalette(p)

    def _enter_fadeout(self):
        p = self.timeDisplay.palette()
        p.setColor(p.WindowText, QColor(255, 50, 50))
        self.timeDisplay.setPalette(p)

    def _exit_fade(self):
        self.timeDisplay.setPalette(self.timeBar.palette())

    def _status_stopped(self):
        self.statusIcon.setPixmap(CueWidget.STOP.pixmap(CueWidget.ICON_SIZE,
                                                        CueWidget.ICON_SIZE))
        self._update_time(0, True)

    def _status_playing(self):
        self.statusIcon.setPixmap(CueWidget.START.pixmap(CueWidget.ICON_SIZE,
                                                         CueWidget.ICON_SIZE))

    def _status_paused(self):
        self.statusIcon.setPixmap(CueWidget.PAUSE.pixmap(CueWidget.ICON_SIZE,
                                                         CueWidget.ICON_SIZE))

    def _status_error(self, cue, error, details):
        self.statusIcon.setPixmap(CueWidget.ERROR.pixmap(CueWidget.ICON_SIZE,
                                                         CueWidget.ICON_SIZE))
        QDetailedMessageBox.dcritical(self.cue.name, error, details)

    def _update_duration(self, duration):
        # Update the maximum values of seek-slider and time progress-bar
        if duration > 0:
            if not self.timeBar.isVisible():
                self.layout().addWidget(self.timeBar, 1, 0, 1, 2)
                self.layout().setRowStretch(1, 1)
                self.timeBar.show()
            self.timeBar.setMaximum(duration)
            self.seekSlider.setMaximum(duration)
        else:
            self.timeBar.hide()
            self.layout().setRowStretch(1, 0)

        # If not in playing or paused update the widget showed time
        if self.cue.state != CueState.Running or self.cue.state != CueState.Running:
            self._update_time(duration, True)

    def _update_time(self, time, ignore_visibility=False):
        if ignore_visibility or not self.visibleRegion().isEmpty():
            # If the given value is the duration or < 0 set the time to 0
            if time == self.cue.duration or time < 0:
                time = 0

            # Set the value the seek slider
            self.seekSlider.setValue(time)

            # If in count-down mode the widget will show the remaining time
            if self._countdown_mode:
                time = self.cue.duration - time

            # Set the value of the timer progress-bar
            if self.cue.duration > 0:
                self.timeBar.setValue(time)

            # Show the time in the widget
            self.timeDisplay.display(strtime(time, accurate=self._accurate_timing))

    def resizeEvent(self, event):
        self.update()

    def update(self):
        super().update()
        self.layout().activate()

        xdim = self.nameButton.width()
        ydim = self.nameButton.height() / 5
        ypos = self.nameButton.height() - ydim

        self.seekSlider.setGeometry(0, ypos, xdim, ydim)
        self.statusIcon.setGeometry(4, 4, CueWidget.ICON_SIZE,
                                    CueWidget.ICON_SIZE)
Ejemplo n.º 42
0
class WindowSR(QMainWindow):
    """Main window of SoundRain"""

    bad_id = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.initWin()
        self.init_client_id()

    def initWin(self):
        """Create main parts of the window"""

        # Main Window
        self.setFixedSize(900, 500)
        self.center()
        self.setWindowTitle("SoundRain")
        self.setWindowIcon(QIcon('soundrainlogo.jpg'))

        # Central Widget
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        # QVBox stocking every row
        self.vertical_grid = QVBoxLayout()

        # First row: URL request
        row_url   = QHBoxLayout()
        label_url = QLabel("URL:", self)
        self.text_url  = QLineEdit(self)
        self.text_url.textChanged.connect(self.block_dl)
        self.but_url   = QPushButton("Search", self)
        self.but_url.clicked.connect(self.check_url)
        row_url.addWidget(label_url)
        row_url.addWidget(self.text_url)
        row_url.addWidget(self.but_url)

        # Row of separation 1
        row_sep1 = QHBoxLayout()
        line_sep = QFrame()
        line_sep.setFrameShape(QFrame.HLine)
        row_sep1.addWidget(line_sep)

        # Second row (splitted screen between cover image and music info): 
        row_split  = QHBoxLayout()
        # Cover image
        column_image = QVBoxLayout()
        self.label_image  = QLabel(self)
        self.label_image.setMaximumHeight(280)
        self.label_image.setMinimumHeight(280)
        self.label_image.setMaximumWidth(280)
        self.label_image.setMinimumHeight(280)
        self.cover = QPixmap(280, 280)
        self.cover.load("unknownperson.jpg")
        self.label_image.setPixmap(self.cover)
        column_image.addWidget(self.label_image)
        # music info
        column_info  = QVBoxLayout()
        label_name   = QLabel("Name", self)
        self.name    = QLineEdit(self)
        label_artist = QLabel("Artist", self)
        self.artist  = QLineEdit(self)
        label_album  = QLabel("Album", self)
        self.album   = QLineEdit(self)
        label_genre  = QLabel("Genre", self)
        self.genre   = QLineEdit(self)
        # --
        column_info.addWidget(label_name)
        column_info.addWidget(self.name)
        column_info.addWidget(label_artist)
        column_info.addWidget(self.artist)
        column_info.addWidget(label_album)
        column_info.addWidget(self.album)
        column_info.addWidget(label_genre)
        column_info.addWidget(self.genre)
        # --
        row_split.addLayout(column_image)
        row_split.addLayout(column_info)

        # Row of separation 2
        row_sep2  = QHBoxLayout()
        line_sep2 = QFrame()
        line_sep2.setFrameShape(QFrame.HLine)
        row_sep2.addWidget(line_sep2)

        # Add the file location selection row
        row_file       = QHBoxLayout()
        self.but_file  = QPushButton("Save location", self)
        self.but_file.clicked.connect(self.open_f)
        self.text_file = QLineEdit(self.default_path(), self)
        row_file.addWidget(self.but_file)
        row_file.addWidget(self.text_file)

        # Row of separation 3
        row_sep3  = QHBoxLayout()
        line_sep3 = QFrame()
        line_sep3.setFrameShape(QFrame.HLine)
        row_sep3.addWidget(line_sep3)

        # Download button row
        row_dl      = QHBoxLayout()
        self.bar_dl = QProgressBar(self)
        self.bar_dl.setFixedSize(600, 30)
        self.bar_dl.setMaximum(100)
        self.bar_dl.setMinimum(0)
        self.bar_dl.hide()
        self.label_dl = QLabel(self)
        self.label_dl.hide()
        self.but_dl = QPushButton("Download", self)
        self.but_dl.clicked.connect(self.manage_download)
        self.but_dl.setDisabled(True)
        row_dl.addWidget(self.bar_dl)
        row_dl.addWidget(self.label_dl)
        row_dl.addStretch(1)
        row_dl.addWidget(self.but_dl)

        # Add every row to the vertical grid
        self.vertical_grid.addLayout(row_url)
        self.vertical_grid.addLayout(row_sep1)
        self.vertical_grid.addLayout(row_split)
        self.vertical_grid.addLayout(row_sep2)
        self.vertical_grid.addLayout(row_file)
        self.vertical_grid.addLayout(row_sep3)
        self.vertical_grid.addLayout(row_dl)

        # Set layout of the vertical grid to the central widget
        self.central_widget.setLayout(self.vertical_grid)

        self.show()

    def init_client_id(self):
        """Ask for client id if it as never been entered, else load it from
        register with QSettings"""

        self.client_id = None
        self.setting   = QSettings(QSettings.UserScope, "BoBibelo",
                                   "SoundRain", self)
        if not self.setting.value("SR_bool"): # Setting never set
            self.client_id_box()
            self.setting.setValue("SR_bool", True)
            self.setting.setValue("SR_id", self.client_id)
        else:
            self.client_id = self.setting.value("SR_id")
        self.client = soundcloud.Client(client_id=self.client_id)

    def client_id_box(self):
        """Generate the client id box"""

        self.client_id_bo = QDialog(self)
        self.client_id_bo.setFixedSize(400, 200)
        self.client_id_bo.setModal(True)

        client_id_grid = QVBoxLayout()
        label_request  = QLabel("Enter your Soundcloud Client ID:", self.client_id_bo)
        self.input_id  = QLineEdit(self.client_id_bo)
        label_help     = QLabel("<a href=\"http://bobibelo.github.io/soundrain/help.html\">Need help ?</a>",
                                self.client_id_bo)
        label_help.setTextFormat(Qt.RichText);
        label_help.setTextInteractionFlags(Qt.TextBrowserInteraction);
        label_help.setOpenExternalLinks(True);

        self.got_id = False
        button_cancel = QPushButton("Cancel", self.client_id_bo)
        button_cancel.clicked.connect(self.reject_id)
        button_accept = QPushButton("Ok", self.client_id_bo)
        button_accept.clicked.connect(self.get_id)
        button_grid   = QHBoxLayout()
        button_grid.addStretch(1)
        button_grid.addWidget(button_cancel)
        button_grid.addWidget(button_accept)

        client_id_grid.addWidget(label_request)
        client_id_grid.addWidget(self.input_id)
        client_id_grid.addWidget(label_help)
        client_id_grid.addLayout(button_grid)
        self.client_id_bo.setLayout(client_id_grid)

        self.client_id_bo.rejected.connect(self.reject_id)
        self.client_id_bo.exec_()

    def get_id(self):
        """Get client id from the qdialog"""

        self.client_id = self.input_id.text().strip()
        if len(self.client_id) != 0:
            self.got_id = True
            self.client_id_bo.close()

    def reject_id(self):
        """Quit app after user not giving client id"""

        if not self.got_id:
            self.close()
            sys.exit(1)

    def open_f(self):
        """Choose the directory where to save music"""

        self.dirname = QFileDialog.getExistingDirectory()
        if self.dirname and len(self.dirname) > 0:
            self.text_file.setText(self.dirname)

    def center(self):
        """Places window in the screen's center"""

        center_geo = self.frameGeometry()
        center_pos = QDesktopWidget().availableGeometry().center()
        center_geo.moveCenter(center_pos)
        self.move(center_geo.topLeft())

    def check_url(self):
        """Test if the music url is correct and if so fill info"""

        url_pattern = "^https?://(www\.)?soundcloud\.com"
        if not re.match(url_pattern, self.text_url.text()):
            QMessageBox.about(self, "Invalid URL",
                              "The requested URL is invalid: %s" % self.text_url.text())
        else:
            self.but_dl.setDisabled(False)
            if "/sets/" in self.text_url.text(): # Is playlist
                self.artist.setText("Not available for playlist.")
                self.name.setText("Not available for playlist.")
                self.disable_input(True)
            elif len(self.text_url.text().split('/')) == 4: # Likes
                self.artist.setText("Not available for likes.")
                self.name.setText("Not available for likes.")
                self.disable_input(False)
            else:
                self.enable_input()
            self.get_music_info()

    def disable_input(self, bo):
        """Disable artist, and name in case of playlist"""

        if bo:
          self.is_playlist = True
          self.is_likes = False
        else:
          self.is_playlist = False
          self.is_likes = True
        self.artist.setDisabled(True)
        self.name.setDisabled(True)

    def enable_input(self):
        """Enable artist, and name after a playlist"""

        self.is_likes = False
        self.is_playlist = False
        self.artist.setDisabled(False)
        self.name.setDisabled(False)

    def get_track(self):
        """Returns track"""

        http_page = httplib2.Http()
        resp = http_page.request(self.url_str, "HEAD")
        if int(resp[0]["status"]) >= 400:
            QMessageBox.about(self,
                              "Error URL",
                              "URL doesn't exist.")
            return False

        try:
            self.track = self.client.get("/resolve", url=self.url_str)
        except:
            self.setting.setValue("SR_bool", False)
            self.init_client_id()
            self.get_track()

        return True

    def get_music_info(self):
        """Get music info, which will be stocked in self.track, and fill info"""

        self.url_str = self.text_url.text()
        if not self.get_track():
            return

        if not self.is_playlist and not self.is_likes:
            self.artist.setText(self.track.user['username'])
            self.name.setText(self.track.title)
            url = self.modifiy_image_size()
            if url:
                self.image = requests.get(url).content
                self.cover.loadFromData(self.image)
            self.cover = self.cover.scaledToWidth(280)
            self.label_image.setPixmap(self.cover)
        else:
            # Get the last part of URL ( == to playlist name)
            self.album.setText(self.text_url.text().rsplit('/', 1)[-1])
            if self.album.text() != "":
                self.text_file.setText("%s/%s" % (self.text_file.text(), self.album.text()))
        if not self.is_likes:
          self.genre.setText(self.track.genre)
        else:
          self.album.setText(self.track.username + "'s favorites")

    def modifiy_image_size(self):
        """Change artwork_url so the image can (potentially) look better"""

        artwork_url = self.track.artwork_url
        if not artwork_url:
            return None
        if "large" in artwork_url:
            return artwork_url.replace("large", "t500x500")
        else:
            return artwork_url

    def manage_download(self):
        """Manage download in case of playlist"""

        if self.is_playlist:
            playlist = self.client.get('/playlists/%s' % (self.track.id))
            count = 1
            self.label_dl.show()
            for song_url in playlist.tracks:
                self.label_dl.setText("%d / %d" % (count, len(playlist.tracks)))
                count += 1
                self.url_str = song_url["permalink_url"]
                self.get_track()
                self.image = requests.get(self.modifiy_image_size()).content
                self.download()
            if len(playlist.tracks) == 0:
                self.fail_box()
            else:
                self.success_box() # Success box for playlist
            self.label_dl.hide()
            self.enable_input()
        elif self.is_likes:
            likes = self.client.get('/users/%s/favorites/' % (self.track.id),
                                    linked_partitioning=1, limit=200)
            set_likes = set()
            while True:
              try:
                link = likes.next_href
              except:
                break
              for like in likes.collection:
                set_likes.add(like)
              likes = self.client.get(link, linked_partitioning=1,
                                      limit=200)
            for like in likes.collection:
              set_likes.add(like)
            count = 1
            self.label_dl.show()
            for like in set_likes:
              self.url_str = like.user['permalink_url']
              self.track = like
              self.label_dl.setText("%d / %d" % (count, len(set_likes)))
              count += 1
              self.image = requests.get(self.modifiy_image_size()).content
              self.download()
              sys.exit(0)
            else:
                self.success_box() # Success box for playlist
            self.label_dl.hide()
            self.enable_input()
        else:
            if self.download():
                self.success_box() # Succes box for single song

        self.reset()

    def download(self):
        """Try to download a single song"""


        self.setDisabled(True)
        self.bar_dl.setDisabled(False)
        self.bar_dl.show()
        try:
            self.fi_mp3, headers = urllib.request.urlretrieve(self.create_url(),
                                                              self.create_filename(),
                                                              reporthook=self.reporthook)
        except:
            self.fail_box()
            self.setDisabled(False)
            self.bar_dl.hide()
            return False

        self.add_tags()
        self.setDisabled(False)
        self.bar_dl.hide()
        return True

    def fail_box(self):
        """Fail box for playlist and single song"""

        if self.is_playlist:
            QMessageBox.about(self, "Error Download",
                              "Playlist '%s' failed to download." % self.text_url.text().rsplit('/', 1)[-1])
        else:
            QMessageBox.about(self, "Error Download",
                              "Download failed for song: %s" % self.track.title)


    def reset(self):
        """Reset all input & image after end of download"""

        self.text_url.setText("")
        self.artist.setText("")
        self.name.setText("")
        self.album.setText("")
        self.genre.setText("")
        self.image = None
        self.cover.load("unknownperson.jpg")
        self.label_image.setPixmap(self.cover)
        self.but_dl.setDisabled(True)
        self.text_file.setText(self.default_path())

    def block_dl(self):
        """Disable download button if user change URL (forces him to re-'search')"""

        self.but_dl.setDisabled(True)

    def add_tags(self):
        """Add artists name, music name, album, genre, and cover"""

        # Set artist name, music name, album, and genre
        audio_file = EasyMP3(self.fi_mp3)
        audio_file.tags = None
        if self.is_playlist:
            audio_file["artist"] = self.track.user["username"]
            audio_file["title"]  = self.track.title
        if self.is_likes:
            audio_file["artist"] = self.track.user["username"]
            audio_file["title"] = self.track.title
        else:
            audio_file["artist"] = self.artist.text()
            audio_file["title"]  = self.name.text()
        audio_file["genre"]  = self.genre.text()
        audio_file["album"]  = self.album.text()
        audio_file.save()

        # Determine the mime
        artwork_url = self.modifiy_image_size()
        if not artwork_url:
            return
        mime = "image/jpeg"
        if ".png" in artwork_url:
            mime = "image/png"

        # Set cover
        audio_file = MP3(self.fi_mp3, ID3=ID3)
        audio_file.tags.add(
                APIC(
                    encoding=3,
                    mime=mime,
                    type=3,
                    desc="Cover",
                    data=self.image
                )
        )
        audio_file.save()

    def success_box(self):
        """Display a sucess box"""

        if self.is_playlist:
            QMessageBox.about(self, "Success",
                              "%s playlist has just been downloaded right into %s"
                              % (self.text_url.text().rsplit('/', 1)[-1], self.text_file.text()))
        else:
            QMessageBox.about(self, "Success",
                              "%s has just been downloaded right into %s"
                              % (self.name.text(), self.text_file.text()))

    def create_url(self):
        url_str = "http://api.soundcloud.com/tracks/%s/stream?client_id=%s" % (self.track.id, self.client_id)
        return url_str

    def create_filename(self):
        path = self.text_file.text()
        if self.is_playlist or self.is_likes:
            name = self.track.title + ".mp3"
        else:
            name = self.name.text() + ".mp3"

        if not os.path.exists(path):
            os.makedirs(path)

        fi_str  = os.path.join(path, name)
        return fi_str

    def default_path(self):
        """Set the default path"""

        list_user = os.listdir("/Users")
        for user in list_user:
            if user != "Shared" and user != ".localized":
                break
        else:
            user = "******"

        path = "/Users/" + user + "/Music"

        return path

    def reporthook(self, blocks_read, block_size, total_size):
        """Tracks the progress of music download"""

        if blocks_read == 0:
            self.bar_dl.setValue(0)
        else:
            amount_read = blocks_read * block_size
            percent     = int((amount_read / total_size) * 100) # Percent of achieved download
            self.bar_dl.setValue(percent)
            QApplication.processEvents()
        return