Esempio n. 1
0
class SystrayIcon(QObject):
    show_window = Signal()
    exit = Signal()

    def __init__(self, parent: QWidget):
        super().__init__(parent)

        # Bold font
        bold = QFont()
        bold.setBold(True)

        # Systray icon
        icon: QIcon = QApplication.instance().windowIcon()
        self._systray_icon = QSystemTrayIcon(icon, self)
        self._systray_icon.setToolTip("Noteeds")

        # Show action
        self._show_action = QAction("&Show", self)
        self._show_action.setFont(bold)

        # Exit action
        self._exit_action = QAction("E&xit", self)

        # Menu
        self._menu = QMenu(parent)
        self._menu.addAction(self._show_action)
        self._menu.addAction(self._exit_action)
        self._systray_icon.setContextMenu(self._menu)

        # Connections
        self._systray_icon.activated.connect(self._activated)
        self._show_action.triggered.connect(self.show_window)
        self._exit_action.triggered.connect(self.exit)

    def _activated(self, reason: QSystemTrayIcon.ActivationReason):
        if reason == QSystemTrayIcon.Trigger:
            self.show_window.emit()

    def show(self):
        self._systray_icon.show()

    def hide(self):
        self._systray_icon.hide()
Esempio n. 2
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. 3
0
class MainWidget(QWidget):
    def __init__(self, app):
        QWidget.__init__(self)
        log.info('Creating MainWidget')

        # Configurar janela e sessão requests
        self.setWindowTitle('Desafio Upload')
        self.setWindowIcon(QIcon("icon.png"))
        self.session = requests.Session()

        # Configurar telas mostradas em StackedLayout
        self.stackedLayout = QStackedLayout()

        self.login_layout = LoginWidget(self.session)
        self.login_layout.did_login.connect(self.go_to_main_ui)
        self.setFixedSize(self.login_layout.size())

        self.main_layout = UploadViewWidget(self.session)

        self.stackedLayout.addWidget(self.login_layout)
        self.stackedLayout.addWidget(self.main_layout)

        self.setLayout(self.stackedLayout)

        # Inicializar variáveis relacionadas ao comportamento de system tray
        self.closeEvent = self.on_close
        self.system_tray = QSystemTrayIcon()
        self.system_tray.setContextMenu(QMenu('Hi!', self))

        # Tray menu
        self.tray = QSystemTrayIcon(QIcon("icon.png"), self)
        self.tray_menu = QMenu(self)

        action_show_window = QAction("Mostrar janela principal", self)
        action_show_window.triggered.connect(self.on_show_main_window)
        self.tray_menu.addAction(action_show_window)

        action_exit = QAction("Fechar", self)
        action_exit.triggered.connect(app.exit)
        self.tray_menu.addAction(action_exit)

        self.tray.setContextMenu(self.tray_menu)
        self.tray.activated.connect(self.on_tray_activated)
        self.tray.hide()

    # # # # # # # # # # # # # # # # # # # #
    # Transição entre telas

    def go_to_main_ui(self, username: str):
        self.main_layout.label_welcome_username.setText(
            f'Bem-vindo, {username}.')
        self.stackedLayout.setCurrentIndex(1)

    # # # # # # # # # # # # # # # # # # # #
    # Interação com o system tray e visibilidade da janela principal

    def on_close(self, event):
        log.info('Moving program to tray')
        self.tray.show()

    def on_show_main_window(self):
        log.info('Moving program from tray to window')
        self.show()
        self.tray.hide()

    def on_tray_activated(self, event: QSystemTrayIcon.ActivationReason):
        if event == QSystemTrayIcon.ActivationReason.Trigger:
            self.on_show_main_window()
Esempio n. 4
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)
Esempio n. 5
0
class KnechtWindow(QMainWindow):
    system_tray_click_connected = False
    tree_focus_changed = Signal(QTreeView)
    is_about_to_quit = Signal()

    def __init__(self, app):
        """ The GUI MainWindow Class

        :param modules.gui.main_app.KnechtApp app: Main QApplication class
        """
        super(KnechtWindow, self).__init__()
        self.app = app
        SetupWidget.from_ui_file(self,
                                 Resource.ui_paths['knecht_model_gui'],
                                 custom_widgets={'QColorButton': QColorButton})

        self.rk_icon = QIcon(QPixmap(Resource.icon_paths['RK_Icon']))

        # Set version window title
        self.setWindowTitle(f'{self.windowTitle()} - v{self.app.version}')

        # ---- Setup Main Menu ----
        self.main_menu = MainWindowMenu(self)

        # ---- Tree Setup ----
        tree_view_list = [self.variantTree, self.renderTree]
        tree_file_list = [_('Variantenbaum'), _('Renderliste')]
        tree_filter_widgets = [
            self.lineEdit_Var_filter, self.lineEdit_Ren_filter
        ]

        # View Mgr will replace placeholder presetTree
        self.view_mgr = UiViewManager(self)
        self.view_mgr.view_updated.connect(self._connect_message_browser)
        self.view_mgr.setup_initial_tab_view(self.presetTree)
        # Set presetTree to current View Mgr view to avoid accessing deleted object
        self.presetTree = self.view_mgr.current_view()

        replaced_views = self.view_mgr.setup_default_views(
            tree_view_list, tree_file_list, tree_filter_widgets)

        self.variantTree, self.renderTree = replaced_views[0], replaced_views[
            1]
        for default_view in [self.variantTree, self.renderTree]:
            default_view.setFocusPolicy(Qt.ClickFocus)
            default_view.undo_stack.cleanChanged.disconnect()

        # ---- Setup renderTree ----
        self.renderTree.is_render_view = True
        self.renderTree.accepted_item_types = [Kg.render_preset, Kg.preset]

        # ---- Internal Clipboard ----
        self.clipboard = TreeClipboard()

        # ---- Store last tree with focus ----
        self.last_focus_tree = self.presetTree

        # ---- System tray and taskbar ----
        self.system_tray = QSystemTrayIcon(self.rk_icon, self)
        self.system_tray.hide()

        # ---- Windows taskbar progress indicator ----
        self.taskbar_btn = QWinTaskbarButton(self)
        self.taskbar_progress = self.taskbar_btn.progress()
        # Delayed Taskbar Setup (Main Window needs to be created for correct window handle)
        QTimer.singleShot(1, self.init_taskbar)

        # ---- Generic Info Overlay ----
        self.overlay = MainWindowOverlay(self.centralWidget())

        # ---- Close Action ----
        self.actionBeenden.triggered.connect(self.close)

        # ---- Setup Main UI Widgets ----
        MainWindowWidgets(self)

        # Updater
        self.updater = KnechtUpdate(self)
        self.updater.update_available.connect(
            self.main_menu.info_menu.update_ready)
        QTimer.singleShot(20000, self.auto_update)  # Initial Update check

        self.app.focusChanged.connect(self.app_focus_changed)

        # ---- Translate Ui elements loaded from ui file ----
        translate_main_ui(self)

        self.setAcceptDrops(True)

    def _get_drop_event_files(self, mime_data):
        files = []
        for url in mime_data.urls():
            if not url.isLocalFile():
                continue

            file = Path(url.toLocalFile())

            if file.suffix.casefold(
            ) in self.main_menu.file_menu.supported_file_types:
                files.append(file)

        return files

    def dragEnterEvent(self, event: QDragEnterEvent):
        if event.mimeData().hasUrls():
            if self._get_drop_event_files(event.mimeData()):
                event.acceptProposedAction()
            else:
                event.ignore()

    def dropEvent(self, event: QDropEvent):
        if event.mimeData().hasUrls():
            files = self._get_drop_event_files(event.mimeData())
            if files:
                for file in files:
                    self.main_menu.file_menu.guess_open_file(file)
                event.accept()
                return True

        event.ignore()
        return False

    def app_focus_changed(self, old_widget: QWidget, new_widget: QWidget):
        if isinstance(new_widget, KnechtTreeView):
            self.set_last_focus_tree(new_widget)

    def init_taskbar(self):
        """ Initializes the MS Windows taskbar button"""
        # Needs to be called after window is created/shown
        self.taskbar_btn.setWindow(self.windowHandle())

        self.taskbar_progress.setRange(0, 100)
        self.taskbar_progress.valueChanged.connect(self.taskbar_progress.show)

    def _connect_message_browser(self, view: KnechtTreeView):
        LOGGER.debug('Setting up message browser for: %s', view.objectName())
        view.info_overlay.setup_message_browser(self.messageBrowser,
                                                self.tabWidget)

    def show_tray_notification(self,
                               title: str,
                               message: str,
                               clicked_callback=None):
        if not self.system_tray.isVisible():
            self.system_tray.show()

        # Disconnect existing callback
        if self.system_tray_click_connected:
            try:
                self.system_tray.messageClicked.disconnect()
            except RuntimeError:
                LOGGER.info(
                    'Could not disconnect system tray messageClicked handler.')
            finally:
                self.system_tray_click_connected = False

        if clicked_callback is not None:
            self.system_tray.messageClicked.connect(clicked_callback)
            self.system_tray_click_connected = True

        self.system_tray.showMessage(title, message, self.rk_icon)

    def set_last_focus_tree(self, set_tree_focus):
        if isinstance(set_tree_focus, KnechtTreeView):
            self.last_focus_tree = set_tree_focus

        self.tree_focus_changed.emit(self.last_focus_tree)

    def tree_with_focus(self) -> KnechtTreeView:
        """ Return the current or last known QTreeView in focus """
        widget_in_focus = self.focusWidget()

        if isinstance(widget_in_focus, KnechtTreeView):
            self.last_focus_tree = widget_in_focus

        return self.last_focus_tree

    def check_for_updates(self):
        self.updater.run_update()

    def auto_update(self):
        if self.updater.first_run:
            if FROZEN:
                self.check_for_updates()

    def report_missing_reset(self):
        msg = _(
            'Die Varianten enthalten keine Reset Schaltung! Die zu sendenden Varianten '
            'werden mit vorangegangen Schaltungen kollidieren.')

        self.overlay.display(msg, duration=5000, immediate=True)

    def msg(self, txt: str, duration: int = 4000) -> None:
        self.statusBar().showMessage(txt, duration)
        self.overlay.display(txt, duration, immediate=True)

    def play_finished_sound(self):
        self._play_sound(SoundRsc.finished)

    def play_confirmation_sound(self):
        self._play_sound(SoundRsc.positive)

    def play_hint_sound(self):
        self._play_sound(SoundRsc.hint)

    def play_warning_sound(self):
        self._play_sound(SoundRsc.warning)

    def _play_sound(self, resource_key):
        try:
            sfx = SoundRsc.get_sound(resource_key, self)
            sfx.play()
        except Exception as e:
            LOGGER.error(e)