Esempio n. 1
0
class SystemTrayIcon(QObject):
    clicked = pyqtSignal()
    double_clicked = pyqtSignal()

    def __init__(self, parent, menu, is_logging=False):
        QObject.__init__(self)

        def getIcon(name):
            return QIcon(':/images/tray_icons/' + name + '.png')

        self._icons = {
            STATUS_INIT: getIcon("disconnected") if is_logging \
                else getIcon("sync"),
            STATUS_DISCONNECTED: getIcon("disconnected"),
            STATUS_WAIT: getIcon("default"),
            STATUS_PAUSE: getIcon("pause"),
            STATUS_IN_WORK: getIcon("sync"),
            STATUS_INDEXING: getIcon("sync"),
        }
        self._statuses = {
            STATUS_INIT: tr("Pvtbox"),
            STATUS_DISCONNECTED: tr("Pvtbox connecting..."),
            STATUS_WAIT: tr("Pvtbox"),
            STATUS_PAUSE: tr("Pvtbox paused"),
            STATUS_IN_WORK: tr("Pvtbox syncing..."),
            STATUS_INDEXING: tr("Pvtbox indexing...")
        }
        self._tray = QSystemTrayIcon(self._icons[STATUS_INIT], parent)
        self.set_tool_tip(self._statuses[STATUS_INIT])
        self._tray.setContextMenu(menu)
        menu.aboutToShow.connect(self.clicked.emit)

        self._tray.activated.connect(self._on_activated)
        self._tray.installEventFilter(self)
        self._tray.setVisible(True)
        self._tray.show()

        self._tray_show_timer = QTimer(self)
        self._tray_show_timer.setInterval(3000)
        self._tray_show_timer.setSingleShot(False)
        self._tray_show_timer.timeout.connect(self.show)

    def eventFilter(self, obj, ev):
        if ev.type() == QEvent.ToolTip:
            self.clicked.emit()
        return False

    def _on_activated(self, reason):
        '''
        Slot for system tray icon activated signal.
        See http://doc.qt.io/qt-5/qsystemtrayicon.html

        @param reason Tray activation reason
        '''

        if reason == QSystemTrayIcon.Trigger:
            # This is usually when left mouse button clicked on tray icon
            self.clicked.emit()
        elif reason == QSystemTrayIcon.DoubleClick:
            self.double_clicked.emit()

    @property
    def menu(self):
        return self._tray.contextMenu()

    def set_tool_tip(self, tip):
        self._tray.setToolTip(tip)

    def show_tray_notification(self, text, title=""):
        if not title:
            title = tr('Pvtbox')
        # Convert strings to unicode
        if type(text) in (str, str):
            text = ensure_unicode(text)
        if type(title) in (str, str):
            title = ensure_unicode(title)

        logger.info("show_tray_notification: %s, title: %s", text, title)
        if self._tray.supportsMessages():
            self._tray.showMessage(title, text)
        else:
            logger.warning("tray does not supports messages")

    def request_to_user(
            self, dialog_id, text, buttons=("Yes", "No"), title="",
            close_button_index=-1, close_button_off=False, parent=None,
            on_clicked_cb=None,
            details=''):

        msg_box = QMessageBox(parent)
        # msg_box = QMessageBox()
        if not title:
            title = tr('Pvtbox')
        msg_box.setWindowTitle(title)
        msg_box.setText(str(text))

        pvtboxIcon = QIcon(':/images/icon.png')
        msg_box.setWindowIcon(pvtboxIcon)

        if details:
            msg_box.setDetailedText(details)

        if close_button_off:
            if get_platform() == 'Darwin':
                msg_box.setWindowFlags(Qt.Tool)
            else:
                msg_box.setWindowFlags(Qt.Dialog |
                                       Qt.CustomizeWindowHint |
                                       Qt.WindowTitleHint)
        msg_box.setAttribute(Qt.WA_MacFrameworkScaled)
        msg_box.setModal(True)

        buttons = list(buttons)
        for button in buttons:
            msg_box.addButton(button, QMessageBox.ActionRole)
        msg_box.show()
        msg_box.raise_()
        msg_box.exec_()
        try:
            button_index = buttons.index(msg_box.clickedButton().text())
        except (ValueError, AttributeError):
            button_index = -1
           # message box was closed with close button
            if len(buttons) == 1 and close_button_index == -1:
                # if only one button then call callback
                close_button_index = 0

            if len(buttons) > close_button_index >= 0:
                button_index = close_button_index

        if button_index >= 0 and callable(on_clicked_cb):
            on_clicked_cb(dialog_id, button_index)

    def update_status_icon(self, new_status, new_substatus):
        icon = self._icons[STATUS_DISCONNECTED] if new_status == STATUS_INIT \
            else self._icons[new_status]
        self._tray.setIcon(icon)
        tool_tip = self._statuses[new_status]
        if new_status == STATUS_IN_WORK and new_substatus == SUBSTATUS_SHARE:
            tool_tip = tr("Pvtbox downloading share...")
        self.set_tool_tip(tool_tip)
        self.show()

    def show(self):
        self._tray.setVisible(True)
        self._tray.show()

    def hide(self):
        if self._tray_show_timer.isActive():
            self._tray_show_timer.stop()
        self._tray.hide()

    def __del__(self):
        self._tray.removeEventFilter(self)
        self._tray.activated.disconnect()
        self.hide()
Esempio n. 2
0
class PingIndicator(QMainWindow):
    def __init__(self, address="8.8.8.8"):
        super(PingIndicator, self).__init__()

        self.icon = QImage(QSize(packet_amount, indicator_image_height),
                           QImage.Format_RGBA8888)

        self.online = True

        self.destination = address

        self.packets = deque([], packet_amount)

        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setToolTip(address)

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(int(timeout * 1.05))
        self.update_timer.timeout.connect(self.update_indicator)

        self.update_timer.start()

        self.last_time_online = strftime("%H:%M:%S")

        self.reset()

    def update_icon(self):
        self.icon.fill(QColor(0, 0, 0, 0))

        painter = QPainter(self.icon)

        (width, height) = self.icon.size().toTuple()
        width -= 1
        height -= 1

        painter.fillRect(QRect(0, 0, width, height), QColor(0, 0, 0, 0))

        try:
            scale = min(1.0 / max(self.packets), min_scale)
        except ValueError:
            scale = min_scale

        for index, ping in enumerate(list(reversed(self.packets))):
            x = ping / float(timeout)

            color = QColor(
                int(-324 * x**2 + 390 * x + 138),  # R
                int(-480 * x**2 + 254 * x + 226),  # G
                int(-212 * x**2 + 160 * x + 52),  # B
                255,
            )

            scaled_height = ceil(scale * ping * height)

            painter.fillRect(
                QRect(width - index, height - scaled_height, 1, scaled_height),
                color)

        self.tray_icon.setIcon(QIcon(QPixmap(self.icon)))
        self.tray_icon.show()

    def update_indicator(self):
        try:
            new_env = dict(os.environ)
            new_env['LC_ALL'] = 'C'

            output = check_output(
                [
                    "ping", "-c", "1", "-W",
                    str(timeout / 1000), self.destination
                ],
                stderr=STDOUT,
                env=new_env,
            ).decode("ascii")  # man ping

            for line in output.splitlines():
                pos = line.find("time=")
                if pos != -1:
                    new_label = line[pos + 5:-3].center(4)
                    self.packets.append(round(float(new_label), 2))

                    if not self.online:
                        self.online = True
                        self.tray_icon.contextMenu().actions()[0].setText(
                            "Last disconnect: " + self.last_time_online)
                    else:
                        self.last_time_online = strftime("%H:%M:%S")

                    break
            else:
                raise ValueError("No time could be parsed.")

        except CalledProcessError as cpe:
            self.packets.append(timeout)

            if self.online:
                self.online = False
                self.tray_icon.contextMenu().actions()[0].setText(
                    "Offline since: " + strftime("%H:%M:%S"))

            print(cpe)
        except KeyboardInterrupt:
            self.close()

        self.update_icon()
        self.update_menu()

        return True

    def reset(self):
        self.packets.clear()
        self.update_icon()

        menu = QMenu()

        menu.addAction("Online since: " + strftime("%H:%M:%S"))
        menu.addAction("Lost: -, Avg: -")
        menu.addAction("Max: -, Min: -")
        menu.addSeparator()
        menu.addAction("Reset").triggered.connect(self.reset)
        menu.addAction("Quit").triggered.connect(self.close)

        self.tray_icon.setContextMenu(menu)

    def update_menu(self):
        self.tray_icon.contextMenu().actions()[1].setText(
            "Lost: %d, Avg: %dms" %
            (self.packets.count(timeout), avg(self.packets)), )
        self.tray_icon.contextMenu().actions()[2].setText(
            "Max: %dms, Min: %dms" % (max(self.packets), min(self.packets)), )
Esempio n. 3
0
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.streamfile = ""
        self.streams = {}
        scriptdir = os.path.dirname(os.path.realpath(__file__))
        icon = (scriptdir + os.path.sep + "icon/pyradio.ico")
        self.setWindowIcon(QtGui.QIcon(icon))
        self.setStuff()
        # Tray
        self.tray = QSystemTrayIcon()
        self.tray.setIcon(QtGui.QIcon(icon))
        self.tray.activated.connect(self.call)

        self.icon = QtGui.QIcon()
        self.icon.addFile(icon)
        self.setWindowIcon(self.icon)

        # tray menu
        self.trayIconMenu = QtWidgets.QMenu()
        self.quitAction = QtWidgets.QAction("&Quit", triggered=self.close)
        self.trayIconMenu.addAction(self.quitAction)
        self.tray.setContextMenu(self.trayIconMenu)
        self.trayIconMenu.setStyleSheet(open("css/main.css", "r").read())

        # Media player
        self.radio = vlc.MediaPlayer()
        self.playing = False

        self.pal = QtGui.QPalette(self.palette())

        self.playing_label = QLabel("Stopped")
        self.label = QLabel("Radios:")

        self.label.setAlignment(Qt.AlignCenter)
        self.playing_label.setAlignment(Qt.AlignCenter)
        self.btn = QPushButton("Play/Stop")
        self.btn.clicked.connect(self.control)
        self.list = QListWidget()
        self.list.itemDoubleClicked.connect(self.control)

        self.edit = QPushButton("Edit Radios")
        self.edit.clicked.connect(self.openfile)
        self.refresh = QPushButton("Refresh")
        self.refresh.clicked.connect(self.refreshstreams)

        self.slider = QSlider(QtGui.Qt.Horizontal)
        self.slider.setMaximum(100)
        self.slider.setValue(self.volume)
        self.slider.valueChanged.connect(self.changeVolume)

        self.setStyleSheet(open("css/main.css", "r").read())

        self.refreshstreams()

        self.current = ""
        self.buttons = QHBoxLayout()

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.label)
        self.layout.addWidget(self.list)
        self.layout.addWidget(self.playing_label)
        self.layout.addWidget(self.slider)
        self.buttons.addWidget(self.btn)
        self.buttons.addWidget(self.edit)
        self.buttons.addWidget(self.refresh)

        self.layout.addLayout(self.buttons)
        self.setLayout(self.layout)

    def setStuff(self):
        info = self.readInfo()
        print(info)
        if len(info) == 0:
            info = ["", "", "", "", ""]
        if (info[0] == ""):
            self.volume = 80
        else:
            self.volume = int(info[0])
        if info[3].strip() == "false" or info[3] == "":
            if info[1] == "":
                self.resize(800, 600)
            else:
                w, h = info[1].split(" ")
                self.resize(int(w), int(h))
            if info[2] != "":
                x, y = info[2].split(" ")
                self.move(int(x), int(y))
        else:
            self.showMaximized()
        if len(info) < 5:
            # show dialog
            self.chooseStreamfile()
        else:
            self.streamfile = info[4].strip()

    def chooseStreamfile(self):
        self.dialog = QFileDialog(self)
        self.dialog.setFileMode(QFileDialog.AnyFile)
        if self.dialog.exec_():
            filename = self.dialog.selectedFiles()
            self.streamfile = filename[0]

    def changeVolume(self):
        self.volume = self.slider.value()
        self.radio.audio_set_volume(self.volume)

    def getVolume(self):
        try:
            with open("data", "r") as file:
                return int(file.readline())
        except:
            with open("data", "w") as file:
                file.write(str(80))
                return 80

    def control(self):
        if self.playing and self.current == self.streams[
                self.list.currentItem().text()]:
            self.stop()
        else:
            self.radio.stop()
            self.play()

    def stop(self):
        self.radio.stop()
        self.playing_label.setText("Stopped")
        self.playing = False

    def play(self):
        self.current = self.list.currentItem().text()
        for i in self.streams:
            if self.current == i:
                self.current = self.streams[i]
                break
        self.radio = vlc.MediaPlayer(self.current)
        self.radio.play()
        self.radio.audio_set_volume(self.slider.value())
        self.playing_label.setText("Playing")
        self.playing = True
        self.tray.showMessage(self.list.currentItem().text(), "",
                              self.tray.icon(), 1000)

    def next(self):
        isthis = False
        self.current = self.list.currentItem().text()
        for n, i in enumerate(self.streams):
            if isthis:
                self.list.setCurrentRow(n)
                break
            else:
                if self.current == i:
                    isthis = True
                    if n + 1 >= len(self.streams):
                        self.list.setCurrentRow(0)
        self.stop()
        self.play()

    def previous(self):
        isthis = False
        self.current = self.list.currentItem().text()
        for n, i in enumerate(self.streams):
            if isthis:
                self.list.setCurrentRow(n - 2)
                break
            else:
                if self.current == i:
                    isthis = True
                    if n - 1 < 0:
                        self.list.setCurrentRow(len(self.streams) - 1)
                        break
                    elif n == len(self.streams) - 1:
                        self.list.setCurrentRow(n - 1)

        self.stop()
        self.play()

    def openfile(self):
        # Opens radios.txt
        webbrowser.open(self.streamfile)

    def refreshstreams(self):

        # Refreshes the stream list when button pressed
        if self.list.currentItem():
            current = self.list.currentItem().text()
        else:
            current = None
        self.streams = {}
        try:
            with open(self.streamfile, "r") as file:
                lines = file.readlines()
                for line in lines:
                    nline = line.strip().split(":", 1)
                    self.streams[nline[0]] = nline[1].split("#")[0]
        except:
            self.chooseStreamfile()
            self.refreshstreams()
            return

        self.list.clear()

        for i, n in enumerate(self.streams):
            self.list.addItem(n)
            if n == current:
                self.list.setCurrentRow(i)
        if not self.list.currentItem():
            self.list.setCurrentRow(0)

    def changeEvent(self, event):

        # This minimizes the program to tray when Minimize button pressed

        if event.type() == QEvent.WindowStateChange:
            if self.windowState() & Qt.WindowMinimized:
                print(QSystemTrayIcon.isSystemTrayAvailable())
                if QSystemTrayIcon.isSystemTrayAvailable(
                ) and self.isActiveWindow():
                    event.ignore()
                    self.tray.show()
                    self.hide()
                    self.listener = keyboard.Listener(
                        on_release=self.on_release)
                    self.listener.start()

    def closeEvent(self, event):
        file = open("data", "w+")
        info = str(self.volume) + "\n" + str(self.size().width()) + " " + str(self.size().height()) + "\n" +\
               str(self.pos().x()) + " " + str(self.pos().y()) + "\n"
        if (self.isMaximized()):
            info += "true"
        else:
            info += "false"
        info += "\n"
        info += self.streamfile + "\n"
        file.write(info)
        file.close()

    def readInfo(self):
        try:
            with open("data", "r", encoding="utf-8") as file:
                info = file.readlines()
                return info
        except:
            with open("data", "w", encoding="utf-8") as file:
                file.write("")
                return ""

    def keyReleaseEvent(self, event):

        # This is for media controls when radio is opened

        key = event.key()
        if key == Qt.Key_MediaPlay or key == Qt.Key_MediaTogglePlayPause or \
                key == Qt.Key_MediaPause:
            self.control()
        elif key == Qt.Key_MediaNext:
            self.next()
        elif key == Qt.Key_MediaPrevious:
            self.previous()

    def call(self, reason):
        # This is caled when tray icon is pressed
        if reason == QSystemTrayIcon.ActivationReason.Trigger:
            self.show()
            self.setFocus()
            self.listener.stop()
            del self.listener
            self.tray.hide()
            self.setWindowState(Qt.WindowActive)
        elif reason == QSystemTrayIcon.ActivationReason.Context:
            self.tray.contextMenu().show()
        elif reason == QSystemTrayIcon.ActivationReason.MiddleClick:
            print("Middle click on tray icon")
        else:
            print("Unknown reason")

    def on_release(self, key):
        # This is for media controls when program in tray.
        try:
            if key == keyboard.Key.media_play_pause:  # might need a different key
                self.control()
            elif keyboard.Key.media_next == key:  # might need a different key
                self.next()
            elif keyboard.Key.media_previous == key:  # might need a different key
                self.previous()
        except AttributeError as e:
            print(e)