Ejemplo n.º 1
0
class FindToolBar(QToolBar):

    find = QtCore.Signal(str, QWebEnginePage.FindFlags)

    def __init__(self):
        super(FindToolBar, self).__init__()
        self._line_edit = QLineEdit()
        self._line_edit.setClearButtonEnabled(True)
        self._line_edit.setPlaceholderText("Find...")
        self._line_edit.setMaximumWidth(300)
        self._line_edit.returnPressed.connect(self._find_next)
        self.addWidget(self._line_edit)

        self._previous_button = QToolButton()
        self._previous_button.setIcon(
            QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png'))
        self._previous_button.clicked.connect(self._find_previous)
        self.addWidget(self._previous_button)

        self._next_button = QToolButton()
        self._next_button.setIcon(
            QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png'))
        self._next_button.clicked.connect(self._find_next)
        self.addWidget(self._next_button)

        self._case_sensitive_checkbox = QCheckBox('Case Sensitive')
        self.addWidget(self._case_sensitive_checkbox)

        self._hideButton = QToolButton()
        self._hideButton.setShortcut(QKeySequence(Qt.Key_Escape))
        self._hideButton.setIcon(
            QIcon(':/qt-project.org/styles/macstyle/images/closedock-16.png'))
        self._hideButton.clicked.connect(self.hide)
        self.addWidget(self._hideButton)

    def focus_find(self):
        self._line_edit.setFocus()

    def _emit_find(self, backward):
        needle = self._line_edit.text().strip()
        if needle:
            flags = QWebEnginePage.FindFlags()
            if self._case_sensitive_checkbox.isChecked():
                flags |= QWebEnginePage.FindCaseSensitively
            if backward:
                flags |= QWebEnginePage.FindBackward
            self.find.emit(needle, flags)

    def _find_next(self):
        self._emit_find(False)

    def _find_previous(self):
        self._emit_find(True)
Ejemplo n.º 2
0
class SearchBar(QWidget):
    QueryLaunched = Signal(str)
    StopPressed = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)

        self._query_edit = QLineEdit()
        self._query_edit.setClearButtonEnabled(True)
        self._query_edit.setPlaceholderText("Type you query here")
        self._query_edit.returnPressed.connect(self._HandleReturnPressed)
        self._query_edit.addAction(QIcon(icons.SEARCH),
                                   QLineEdit.LeadingPosition)

        self._kill_button = QToolButton()
        self._kill_button.setIcon(QIcon(icons.STOP))
        self._kill_button.setAutoRaise(True)
        self._kill_button.setMinimumSize(31, 31)
        self._kill_button.setEnabled(False)
        self._kill_button.clicked.connect(self.StopPressed)

        layout = QHBoxLayout()
        layout.addWidget(self._kill_button)
        layout.addWidget(self._query_edit)
        layout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(layout)

        self.setFocusProxy(self._query_edit)

    def Clear(self):
        self._query_edit.clear()

    def SetStopEnabled(self, bool_):
        self._kill_button.setEnabled(bool_)

    def SetQueryEditEnabled(self, bool_):
        self._query_edit.setEnabled(bool_)

    def SetQuery(self, query):
        self._query_edit.setText(query)

    def LaunchQuery(self, query):
        self._query_edit.setText(query)
        self._HandleReturnPressed()

    def _HandleReturnPressed(self):
        query = " ".join(self._query_edit.text().split())

        if query == "":
            return

        self.QueryLaunched.emit(query)
Ejemplo n.º 3
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        centralWidget = QWidget()
        self.setCentralWidget(centralWidget)
        layout = QFormLayout(centralWidget)

        textLayout = QHBoxLayout()
        self.text = QLineEdit('Hello, PySide2')
        self.text.setClearButtonEnabled(True)
        textLayout.addWidget(self.text)
        self.sayButton = QPushButton('Say')
        textLayout.addWidget(self.sayButton)
        self.text.returnPressed.connect(self.sayButton.animateClick)
        self.sayButton.clicked.connect(self.say)
        layout.addRow('Text:', textLayout)

        self.voiceCombo = QComboBox()
        layout.addRow('Voice:', self.voiceCombo)

        self.volumeSlider = QSlider(Qt.Horizontal)
        self.volumeSlider.setMinimum(0)
        self.volumeSlider.setMaximum(100)
        self.volumeSlider.setValue(100)
        layout.addRow('Volume:', self.volumeSlider)

        self.engine = None
        engineNames = QTextToSpeech.availableEngines()
        if len(engineNames) > 0:
            engineName = engineNames[0]
            self.engine = QTextToSpeech(engineName)
            self.engine.stateChanged.connect(self.stateChanged)
            self.setWindowTitle(
                'QTextToSpeech Example ({})'.format(engineName))
            self.voices = []
            for voice in self.engine.availableVoices():
                self.voices.append(voice)
                self.voiceCombo.addItem(voice.name())
        else:
            self.setWindowTitle('QTextToSpeech Example (no engines available)')
            self.sayButton.setEnabled(False)

    def say(self):
        self.sayButton.setEnabled(False)
        self.engine.setVoice(self.voices[self.voiceCombo.currentIndex()])
        self.engine.setVolume(float(self.volumeSlider.value()) / 100)
        self.engine.say(self.text.text())

    def stateChanged(self, state):
        if (state == QTextToSpeech.State.Ready):
            self.sayButton.setEnabled(True)
Ejemplo n.º 4
0
class Browser_Toolbar(QToolBar):
    def __init__(self):
        QToolBar.__init__(self)
        self.back = QPushButton("back")
        self.next = QPushButton("next")
        self.reload = QPushButton("reload")
        self.url_box = QLineEdit(self)
        self.url_box.setClearButtonEnabled(True)
        
        self.addWidget(self.back)
        self.addWidget(self.next)
        self.addWidget(self.reload)
        self.addWidget(self.url_box)
Ejemplo n.º 5
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        # Initialize main widget
        centralWidget = QWidget()
        self.setCentralWidget(centralWidget)
        layout = QFormLayout(centralWidget)

        # QLineEdit example
        textLayout = QHBoxLayout()
        self.text = QLineEdit('Hello, PySide2')
        self.text.setClearButtonEnabled(True)
        textLayout.addWidget(self.text)
        self.btn = QPushButton('Say')
        textLayout.addWidget(self.btn)
        self.text.returnPressed.connect(self.btn.animateClick)
        self.btn.clicked.connect(self.say)
        layout.addRow('Text:', textLayout)

        # QComboBox example
        self.combo = QComboBox()
        self.combo.addItems(items)
        layout.addRow('Item:', self.combo)
        self.combo.currentIndexChanged.connect(self.selected)

        # QSlide example
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMinimum(0)
        self.slider.setMaximum(100)
        self.slider.setValue(100)
        self.slider.valueChanged.connect(self.slide)
        layout.addRow('Volume:', self.slider)

        # QLabel example
        self.label = QLabel()
        self.label.setText('')
        layout.addRow('Result:', self.label)

    # button event handler
    def say(self):
        text = self.text.text()
        self.label.setText(text)

    # combobox event handler
    def selected(self, index):
        self.label.setText(items[index])

    # slider event handler
    def slide(self, value):
        self.label.setText(str(value))
Ejemplo n.º 6
0
class FindToolBar(QToolBar):

    find = QtCore.Signal(str, QWebEnginePage.FindFlags)

    def __init__(self):
        super(FindToolBar, self).__init__()
        self._line_edit = QLineEdit()
        self._line_edit.setClearButtonEnabled(True)
        self._line_edit.setPlaceholderText("Find...")
        self._line_edit.setMaximumWidth(300)
        self._line_edit.returnPressed.connect(self._find_next)
        self.addWidget(self._line_edit)

        self._previous_button = QToolButton()
        self._previous_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/up-32.png'))
        self._previous_button.clicked.connect(self._find_previous)
        self.addWidget(self._previous_button)

        self._next_button = QToolButton()
        self._next_button.setIcon(QIcon(':/qt-project.org/styles/commonstyle/images/down-32.png'))
        self._next_button.clicked.connect(self._find_next)
        self.addWidget(self._next_button)

        self._case_sensitive_checkbox = QCheckBox('Case Sensitive')
        self.addWidget(self._case_sensitive_checkbox)

        self._hideButton = QToolButton()
        self._hideButton.setShortcut(QKeySequence(Qt.Key_Escape))
        self._hideButton.setIcon(QIcon(':/qt-project.org/styles/macstyle/images/closedock-16.png'))
        self._hideButton.clicked.connect(self.hide)
        self.addWidget(self._hideButton)

    def focus_find(self):
        self._line_edit.setFocus()

    def _emit_find(self, backward):
        needle =  self._line_edit.text().strip()
        if needle:
            flags = QWebEnginePage.FindFlags()
            if self._case_sensitive_checkbox.isChecked():
                flags |= QWebEnginePage.FindCaseSensitively
            if backward:
                flags |= QWebEnginePage.FindBackward
            self.find.emit(needle, flags)

    def _find_next(self):
        self._emit_find(False)

    def _find_previous(self):
        self._emit_find(True)
Ejemplo n.º 7
0
class MainWindow(QMainWindow):
    """Provides the parent window that includes the BookmarkWidget,
    BrowserTabWidget, and a DownloadWidget, to offer the complete
    web browsing experience."""
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('PySide2 tabbed browser Example')

        self._tab_widget = BrowserTabWidget(create_main_window_with_browser)
        self._tab_widget.enabled_changed.connect(self._enabled_changed)
        self._tab_widget.download_requested.connect(self._download_requested)
        self.setCentralWidget(self._tab_widget)
        self.connect(self._tab_widget, QtCore.SIGNAL("url_changed(QUrl)"),
                     self.url_changed)

        self._bookmark_dock = QDockWidget()
        self._bookmark_dock.setWindowTitle('Bookmarks')
        self._bookmark_widget = BookmarkWidget()
        self._bookmark_widget.open_bookmark.connect(self.load_url)
        self._bookmark_widget.open_bookmark_in_new_tab.connect(
            self.load_url_in_new_tab)
        self._bookmark_dock.setWidget(self._bookmark_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self._bookmark_dock)

        self._find_tool_bar = None

        self._actions = {}
        self._create_menu()

        self._tool_bar = QToolBar()
        self.addToolBar(self._tool_bar)
        for action in self._actions.values():
            if not action.icon().isNull():
                self._tool_bar.addAction(action)

        self._addres_line_edit = QLineEdit()
        self._addres_line_edit.setClearButtonEnabled(True)
        self._addres_line_edit.returnPressed.connect(self.load)
        self._tool_bar.addWidget(self._addres_line_edit)
        self._zoom_label = QLabel()
        self.statusBar().addPermanentWidget(self._zoom_label)
        self._update_zoom_label()

        self._bookmarksToolBar = QToolBar()
        self.addToolBar(Qt.TopToolBarArea, self._bookmarksToolBar)
        self.insertToolBarBreak(self._bookmarksToolBar)
        self._bookmark_widget.changed.connect(self._update_bookmarks)
        self._update_bookmarks()

    def _update_bookmarks(self):
        self._bookmark_widget.populate_tool_bar(self._bookmarksToolBar)
        self._bookmark_widget.populate_other(self._bookmark_menu, 3)

    def _create_menu(self):
        file_menu = self.menuBar().addMenu("&File")
        exit_action = QAction(QIcon.fromTheme("application-exit"),
                              "E&xit",
                              self,
                              shortcut="Ctrl+Q",
                              triggered=qApp.quit)
        file_menu.addAction(exit_action)

        navigation_menu = self.menuBar().addMenu("&Navigation")

        style_icons = ':/qt-project.org/styles/commonstyle/images/'
        back_action = QAction(QIcon.fromTheme(
            "go-previous", QIcon(style_icons + 'left-32.png')),
                              "Back",
                              self,
                              shortcut=QKeySequence(QKeySequence.Back),
                              triggered=self._tab_widget.back)
        self._actions[QWebEnginePage.Back] = back_action
        back_action.setEnabled(False)
        navigation_menu.addAction(back_action)
        forward_action = QAction(QIcon.fromTheme(
            "go-next", QIcon(style_icons + 'right-32.png')),
                                 "Forward",
                                 self,
                                 shortcut=QKeySequence(QKeySequence.Forward),
                                 triggered=self._tab_widget.forward)
        forward_action.setEnabled(False)
        self._actions[QWebEnginePage.Forward] = forward_action

        navigation_menu.addAction(forward_action)
        reload_action = QAction(QIcon(style_icons + 'refresh-32.png'),
                                "Reload",
                                self,
                                shortcut=QKeySequence(QKeySequence.Refresh),
                                triggered=self._tab_widget.reload)
        self._actions[QWebEnginePage.Reload] = reload_action
        reload_action.setEnabled(False)
        navigation_menu.addAction(reload_action)

        navigation_menu.addSeparator()

        new_tab_action = QAction("New Tab",
                                 self,
                                 shortcut='Ctrl+T',
                                 triggered=self.add_browser_tab)
        navigation_menu.addAction(new_tab_action)

        close_tab_action = QAction("Close Current Tab",
                                   self,
                                   shortcut="Ctrl+W",
                                   triggered=self._close_current_tab)
        navigation_menu.addAction(close_tab_action)

        edit_menu = self.menuBar().addMenu("&Edit")

        find_action = QAction("Find",
                              self,
                              shortcut=QKeySequence(QKeySequence.Find),
                              triggered=self._show_find)
        edit_menu.addAction(find_action)

        edit_menu.addSeparator()
        undo_action = QAction("Undo",
                              self,
                              shortcut=QKeySequence(QKeySequence.Undo),
                              triggered=self._tab_widget.undo)
        self._actions[QWebEnginePage.Undo] = undo_action
        undo_action.setEnabled(False)
        edit_menu.addAction(undo_action)

        redo_action = QAction("Redo",
                              self,
                              shortcut=QKeySequence(QKeySequence.Redo),
                              triggered=self._tab_widget.redo)
        self._actions[QWebEnginePage.Redo] = redo_action
        redo_action.setEnabled(False)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction("Cut",
                             self,
                             shortcut=QKeySequence(QKeySequence.Cut),
                             triggered=self._tab_widget.cut)
        self._actions[QWebEnginePage.Cut] = cut_action
        cut_action.setEnabled(False)
        edit_menu.addAction(cut_action)

        copy_action = QAction("Copy",
                              self,
                              shortcut=QKeySequence(QKeySequence.Copy),
                              triggered=self._tab_widget.copy)
        self._actions[QWebEnginePage.Copy] = copy_action
        copy_action.setEnabled(False)
        edit_menu.addAction(copy_action)

        paste_action = QAction("Paste",
                               self,
                               shortcut=QKeySequence(QKeySequence.Paste),
                               triggered=self._tab_widget.paste)
        self._actions[QWebEnginePage.Paste] = paste_action
        paste_action.setEnabled(False)
        edit_menu.addAction(paste_action)

        edit_menu.addSeparator()

        select_all_action = QAction("Select All",
                                    self,
                                    shortcut=QKeySequence(
                                        QKeySequence.SelectAll),
                                    triggered=self._tab_widget.select_all)
        self._actions[QWebEnginePage.SelectAll] = select_all_action
        select_all_action.setEnabled(False)
        edit_menu.addAction(select_all_action)

        self._bookmark_menu = self.menuBar().addMenu("&Bookmarks")
        add_bookmark_action = QAction("&Add Bookmark",
                                      self,
                                      triggered=self._add_bookmark)
        self._bookmark_menu.addAction(add_bookmark_action)
        add_tool_bar_bookmark_action = QAction(
            "&Add Bookmark to Tool Bar",
            self,
            triggered=self._add_tool_bar_bookmark)
        self._bookmark_menu.addAction(add_tool_bar_bookmark_action)
        self._bookmark_menu.addSeparator()

        tools_menu = self.menuBar().addMenu("&Tools")
        download_action = QAction(
            "Open Downloads",
            self,
            triggered=DownloadWidget.open_download_directory)
        tools_menu.addAction(download_action)

        window_menu = self.menuBar().addMenu("&Window")

        window_menu.addAction(self._bookmark_dock.toggleViewAction())

        window_menu.addSeparator()

        zoom_in_action = QAction(QIcon.fromTheme("zoom-in"),
                                 "Zoom In",
                                 self,
                                 shortcut=QKeySequence(QKeySequence.ZoomIn),
                                 triggered=self._zoom_in)
        window_menu.addAction(zoom_in_action)
        zoom_out_action = QAction(QIcon.fromTheme("zoom-out"),
                                  "Zoom Out",
                                  self,
                                  shortcut=QKeySequence(QKeySequence.ZoomOut),
                                  triggered=self._zoom_out)
        window_menu.addAction(zoom_out_action)

        reset_zoom_action = QAction(QIcon.fromTheme("zoom-original"),
                                    "Reset Zoom",
                                    self,
                                    shortcut="Ctrl+0",
                                    triggered=self._reset_zoom)
        window_menu.addAction(reset_zoom_action)

        about_menu = self.menuBar().addMenu("&About")
        about_action = QAction("About Qt",
                               self,
                               shortcut=QKeySequence(
                                   QKeySequence.HelpContents),
                               triggered=qApp.aboutQt)
        about_menu.addAction(about_action)

    def add_browser_tab(self):
        return self._tab_widget.add_browser_tab()

    def _close_current_tab(self):
        if self._tab_widget.count() > 1:
            self._tab_widget.close_current_tab()
        else:
            self.close()

    def close_event(self, event):
        main_windows.remove(self)
        event.accept()

    def load(self):
        url_string = self._addres_line_edit.text().strip()
        if url_string:
            self.load_url_string(url_string)

    def load_url_string(self, url_s):
        url = QUrl.fromUserInput(url_s)
        if (url.isValid()):
            self.load_url(url)

    def load_url(self, url):
        self._tab_widget.load(url)

    def load_url_in_new_tab(self, url):
        self.add_browser_tab().load(url)

    def url_changed(self, url):
        self._addres_line_edit.setText(url.toString())

    def _enabled_changed(self, web_action, enabled):
        action = self._actions[web_action]
        if action:
            action.setEnabled(enabled)

    def _add_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_bookmark(url, title, icon)

    def _add_tool_bar_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_tool_bar_bookmark(url, title, icon)

    def _zoom_in(self):
        new_zoom = self._tab_widget.zoom_factor() * 1.5
        if (new_zoom <= WebEngineView.maximum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _zoom_out(self):
        new_zoom = self._tab_widget.zoom_factor() / 1.5
        if (new_zoom >= WebEngineView.minimum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _reset_zoom(self):
        self._tab_widget.set_zoom_factor(1)
        self._update_zoom_label()

    def _update_zoom_label(self):
        percent = int(self._tab_widget.zoom_factor() * 100)
        self._zoom_label.setText("{}%".format(percent))

    def _download_requested(self, item):
        # Remove old downloads before opening a new one
        for old_download in self.statusBar().children():
            if type(old_download).__name__ == 'download_widget' and \
                old_download.state() != QWebEngineDownloadItem.DownloadInProgress:
                self.statusBar().removeWidget(old_download)
                del old_download

        item.accept()
        download_widget = download_widget(item)
        download_widget.removeRequested.connect(
            self._remove_download_requested, Qt.QueuedConnection)
        self.statusBar().addWidget(download_widget)

    def _remove_download_requested(self):
        download_widget = self.sender()
        self.statusBar().removeWidget(download_widget)
        del download_widget

    def _show_find(self):
        if self._find_tool_bar is None:
            self._find_tool_bar = FindToolBar()
            self._find_tool_bar.find.connect(self._tab_widget.find)
            self.addToolBar(Qt.BottomToolBarArea, self._find_tool_bar)
        else:
            self._find_tool_bar.show()
        self._find_tool_bar.focus_find()

    def write_bookmarks(self):
        self._bookmark_widget.write_bookmarks()
Ejemplo n.º 8
0
class AddPerson(QWidget):
    def __init__(self, parent):
        QWidget.__init__(self)
        self.setWindowTitle("Add person")
        self.setWindowIcon(QIcon("assets/icons/icon.ico"))
        self.setGeometry(450, 150, 400, 250)
        # self.setFixedSize(self.size())

        self.Parent = parent

        self.filePathName = ""

        self.UI()
        self.show()

    def UI(self):
        self.widgets()
        self.layouts()

    def widgets(self):
        # Top layout widgets
        self.addPersonImg = QLabel()
        self.img = QPixmap('assets/icons/edit-item.png')
        self.addPersonImg.setPixmap(self.img)
        self.addPersonImg.setAlignment(Qt.AlignCenter)
        self.titleText = QLabel("ADD PERSON")
        self.titleText.setObjectName("add_person_title_txt")
        self.titleText.setAlignment(Qt.AlignCenter)
        # Bottom layout widgets
        self.firstNameEntry = QLineEdit()
        self.firstNameEntry.setClearButtonEnabled(True)
        self.lastNameEntry = QLineEdit()
        self.lastNameEntry.setClearButtonEnabled(True)
        self.titleEntry = QLineEdit()
        self.titleEntry.setClearButtonEnabled(True)
        self.phoneEntry = QLineEdit()
        self.phoneEntry.setClearButtonEnabled(True)
        self.emailEntry = QLineEdit()
        self.emailEntry.setClearButtonEnabled(True)
        self.locationEntry = QLineEdit()
        self.locationEntry.setClearButtonEnabled(True)

        emplTypes = ["Employee", "Contractor", "Subcontractor"]
        self.employmentTypeEntry = QComboBox()
        self.employmentTypeEntry.addItems(emplTypes)
        self.employmentTypeEntry.setEditable(True)

        self.attachPhotoBtn = QPushButton("Attach photo")
        self.attachPhotoBtn.clicked.connect(self.funcAttachFiles)

        self.addPersonBtn = QPushButton("Add person")
        self.addPersonBtn.clicked.connect(self.addPerson)

        self.cancelBtn = QPushButton("Cancel")
        self.cancelBtn.clicked.connect(self.closeWindow)

    def layouts(self):
        self.mainLayout = QVBoxLayout()
        self.topLayout = QHBoxLayout()
        self.bottomLayout = QFormLayout()
        self.bottomLayout.setVerticalSpacing(20)
        self.bottomBtnLayout = QHBoxLayout()

        # Put elements into frames for visual distinction
        self.topFrame = QFrame()
        self.bottomFrame = QFrame()

        # Add widgets to top layout
        # self.topLayout.addWidget(self.addPersonImg)
        self.topLayout.addWidget(self.titleText)

        self.topFrame.setLayout(self.topLayout)

        # Add widgets to middle layout
        self.bottomLayout.addRow(QLabel("First name: "), self.firstNameEntry)
        self.bottomLayout.addRow(QLabel("Last name: "), self.lastNameEntry)
        self.bottomLayout.addRow(QLabel("Title: "), self.titleEntry)
        self.bottomLayout.addRow(QLabel("Phone: "), self.phoneEntry)
        self.bottomLayout.addRow(QLabel("Email: "), self.emailEntry)
        self.bottomLayout.addRow(QLabel("Location: "), self.locationEntry)
        self.bottomLayout.addRow(QLabel("Employment type: "), self.employmentTypeEntry)
        self.bottomLayout.addRow(QLabel(""), self.attachPhotoBtn)

        self.bottomBtnLayout.addWidget(self.cancelBtn)
        self.bottomBtnLayout.addItem(QSpacerItem(200, 5, QSizePolicy.Minimum, QSizePolicy.Expanding))
        self.bottomBtnLayout.addWidget(self.addPersonBtn)
        self.bottomBtnLayout.setAlignment(Qt.AlignBottom)

        self.bottomLayout.addRow(self.bottomBtnLayout)

        self.bottomFrame.setLayout(self.bottomLayout)

        # Add frames to main layout
        self.mainLayout.addWidget(self.topFrame)
        self.mainLayout.addWidget(self.bottomFrame)

        self.setLayout(self.mainLayout)

    @Slot()
    def closeWindow(self):
        self.close()

    @Slot()
    def addPerson(self):
        firstName = self.firstNameEntry.text()
        lastName = self.lastNameEntry.text()
        title = self.titleEntry.text()
        phone = self.phoneEntry.text()
        email = self.emailEntry.text()
        location = self.locationEntry.text()
        emplType = self.employmentTypeEntry.currentText()

        # If user selected a file to attach, rename the file and copy it to media folder
        # Else set the path variables to empty strings to avoid problems with db write
        if self.filePathName != "":
            self.newFilePath = ShCopy2(self.filePathName, self.attachedFilePath)

            im = Image.open(self.filePathName)

            im_resized = self.crop_max_square(im).resize((800, 800), Image.LANCZOS)
            im_resized.save(self.attachedResizedFilePath)

            im_square = self.crop_max_square(im).resize((60, 60), Image.LANCZOS)
            im_thumb = self.mask_circle_transparent(im_square, 60, 60, 2)

            im_thumb.save(self.attachedThumbnailPath)
        else:
            self.attachedFilePath = ""
            self.attachedResizedFilePath = ""
            self.attachedThumbnailPath = ""

        if (firstName and lastName and title and phone and email and location and emplType != ""):
            try:
                query = "INSERT INTO people (person_first_name, person_last_name, person_title, person_phone," \
                        "person_email, person_location, person_empl_type, photo_original_path, photo_resized_path, " \
                        "thumbnail_path) " \
                        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

                db.cur.execute(query, (firstName, lastName, title, phone, email, location, emplType,
                                       self.attachedFilePath, self.attachedResizedFilePath, self.attachedThumbnailPath))

                db.conn.commit()

                self.Parent.funcDisplayPeople()
                QMessageBox.information(self, "Info", "Member has been added")
                self.close()
            except:
                QMessageBox.information(self, "Info", "Member has not been added")
        else:
            QMessageBox.information(self, "Info", "Fields cannot be empty")

    @Slot()
    def funcAttachFiles(self):
        self.filePathName = QFileDialog.getOpenFileName(self, "Attach file...", "/",
                                                        "Image files (*.png *.jpeg *.jpg)")[0]

        if osPath.isfile(self.filePathName):
            fileName, fileExt = osPath.splitext(self.filePathName)

            if fileExt == '.jpg' or fileExt == '.jpeg' or fileExt == '.png':
                date = datetime.now()
                randomSuffix = "".join(random.choice(string.ascii_lowercase) for i in range(15))

                self.attachedFilePath = osPath.join("assets", "media", "people-media", "photos",
                                                     ("{:%d%b%Y_%Hh%Mm}".format(date) + randomSuffix + fileExt))
                self.attachedResizedFilePath = osPath.join("assets", "media", "people-media", "photos_resized",
                                                            ("{:%d%b%Y_%Hh%Mm}".format(date) + randomSuffix + "_resized" + fileExt))
                self.attachedThumbnailPath = osPath.join("assets", "media", "people-media", "photos_thumbnails",
                                                            ("{:%d%b%Y_%Hh%Mm}".format(date) + randomSuffix + "_resized.png"))


                QMessageBox.information(self, "Info", "File attached successfully")

            else:
                QMessageBox.information(self, "Info", "Wrong file type!")
        else:
            QMessageBox.information(self, "Info", "No file selected")

    ################ Image processing functions ##########################################
    def crop_center(self, pil_img, crop_width, crop_height):
        img_width, img_height = pil_img.size

        fill_color = 'rgba(255, 255, 255, 1)'

        if pil_img.mode in ('RGBA', 'LA'):
            background = Image.new(pil_img.mode[:-1], pil_img.size, fill_color)
            background.paste(pil_img, pil_img.split()[-1])
            image = background

        return pil_img.crop(((img_width - crop_width) // 2,
                             (img_height - crop_height) // 2,
                             (img_width + crop_width) // 2,
                             (img_height + crop_height) // 2))

    # Crop the largest possible square from a rectangle
    def crop_max_square(self, pil_img):
        return self.crop_center(pil_img, min(pil_img.size), min(pil_img.size))

    # crop a square image into a circular image
    def mask_circle_transparent(self, pil_img, crop_width, crop_height, blur_radius, offset=0):
        img_width, img_height = pil_img.size
        pil_img.crop(((img_width - crop_width) // 2,
                      (img_height - crop_height) // 2,
                      (img_width + crop_width) // 2,
                      (img_height + crop_height) // 2))

        offset = blur_radius * 2 + offset
        mask = Image.new("L", pil_img.size, 0)
        draw = ImageDraw.Draw(mask)
        draw.ellipse((offset, offset, pil_img.size[0] - offset, pil_img.size[1] - offset), fill=255)
        mask = mask.filter(ImageFilter.GaussianBlur(blur_radius))

        result = pil_img.copy()
        result.putalpha(mask)

        return result
class Artigence(QMainWindow):
    def __init__(self):
        super(Artigence, self).__init__()

        # Basic Settings
        self.setGeometry(300, 200, 682, 422)
        self.setMinimumSize(QSize(682, 422))
        self.setMaximumSize(QSize(682, 422))
        self.setWindowIcon(QIcon("arti.PNG"))
        self.setWindowTitle("Artigence Home")

        # Color Scheme
        self.palette = QPalette()
        self.palette.setColor(self.palette.Window, QColor('#000000'))
        self.palette.setColor(self.palette.WindowText, QColor('#FFFFFF'))
        self.setPalette(self.palette)

        self.light_palette = QPalette()
        self.light_palette.setColor(self.light_palette.Window,
                                    QColor('#FFFFFF'))
        self.light_palette.setColor(self.light_palette.WindowText,
                                    QColor('#000000'))

        # Setting MenuBar
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(0, 0, 682, 21)

        self.date_menu = QMenu(self.menubar)
        self.date_menu.setTitle(str(datetime.now().strftime('%d-%m-%Y')))

        self.theme_menu = QMenu(self.menubar)
        self.theme_menu.setTitle('Theme')

        self.dark_theme = QAction('Dark Theme')
        self.dark_theme.setShortcut(QKeySequence('Ctrl+Shift+D'))
        self.theme_menu.addAction(self.dark_theme)
        self.dark_theme.triggered.connect(lambda: self.dark())

        self.light_theme = QAction('Light Theme')
        self.light_theme.setShortcut(QKeySequence('Ctrl+Shift+L'))
        self.theme_menu.addAction(self.light_theme)
        self.light_theme.triggered.connect(lambda: self.light())

        self.app_menu = QMenu(self.menubar)
        self.app_menu.setTitle('Apps')

        self.calculator_menu = QAction('Calculator')
        self.calculator_menu.setShortcut(QKeySequence('Alt+C'))
        self.app_menu.addAction(self.calculator_menu)
        self.calculator_menu.triggered.connect(lambda: self.calculator_func())

        self.game_menu = QAction('GameHub')
        self.game_menu.setShortcut(QKeySequence('Alt+G'))
        self.app_menu.addAction(self.game_menu)
        self.game_menu.triggered.connect(lambda: self.games_func())

        self.music_menu = QAction('Muse (Music)')
        self.music_menu.setShortcut(QKeySequence('Alt+M'))
        self.app_menu.addAction(self.music_menu)
        self.music_menu.triggered.connect(lambda: self.music_func())

        self.news_menu = QAction('News')
        self.news_menu.setShortcut(QKeySequence('Alt+E'))
        self.app_menu.addAction(self.news_menu)
        self.news_menu.triggered.connect(lambda: self.news_func())

        self.notepad_menu = QAction('Notepad')
        self.notepad_menu.setShortcut(QKeySequence('Alt+N'))
        self.app_menu.addAction(self.notepad_menu)
        self.notepad_menu.triggered.connect(lambda: self.notepad_func())

        self.pronunciator = QAction('Pronunciator')
        self.pronunciator.setShortcut(QKeySequence('Alt+P'))
        self.app_menu.addAction(self.pronunciator)
        self.pronunciator.triggered.connect(lambda: self.pronunciator_func())

        self.translate_menu = QAction('Translate')
        self.translate_menu.setShortcut(QKeySequence('Alt+T'))
        self.app_menu.addAction(self.translate_menu)
        self.translate_menu.triggered.connect(lambda: self.translate_func())

        self.weather_menu = QAction('Weather')
        self.weather_menu.setShortcut(QKeySequence('Alt+W'))
        self.app_menu.addAction(self.weather_menu)
        self.weather_menu.triggered.connect(lambda: self.weather_func())

        self.setMenuBar(self.menubar)
        self.menubar.addAction(self.date_menu.menuAction())
        self.menubar.addAction(self.theme_menu.menuAction())
        self.menubar.addAction(self.app_menu.menuAction())

        # Creating Widgets
        self.query = QLineEdit(self)
        self.query.setGeometry(QRect(20, 30, 451, 41))
        self.query.setMinimumSize(QSize(451, 41))
        self.query.setMaximumSize(QSize(451, 41))
        self.query.setPlaceholderText("Enter your Query Here:")
        self.query.setFont(QFont('Roboto', 16))
        self.query.setClearButtonEnabled(True)

        self.update = QPushButton(self)
        self.update.setGeometry(QRect(491, 30, 171, 41))
        self.update.setMinimumSize(QSize(1, 1))
        self.update.setMaximumSize(QSize(171, 51))
        self.update.setText("What's New in the Updates?")
        self.update.setCursor(QCursor(Qt.PointingHandCursor))

        self.suggestions = QLabel(self)
        self.suggestions.setGeometry(QRect(20, 220, 111, 31))
        self.suggestions.setMinimumSize(QSize(111, 31))
        self.suggestions.setMaximumSize(QSize(111, 31))
        self.suggestions.setText("Suggestions:")
        self.suggestions.setFont(QFont('Roboto', 14))

        self.chrome = QPushButton(self)
        self.chrome.setGeometry(QRect(20, 260, 91, 31))
        self.chrome.setCursor(QCursor(Qt.PointingHandCursor))
        self.chrome.setText('Open Chrome')

        self.games = QPushButton(self)
        self.games.setGeometry(QRect(420, 260, 91, 31))
        self.games.setCursor(QCursor(Qt.PointingHandCursor))
        self.games.setText('Games')

        self.cmd = QPushButton(self)
        self.cmd.setGeometry(QRect(160, 260, 91, 31))
        self.cmd.setCursor(QCursor(Qt.PointingHandCursor))
        self.cmd.setText('Open Cmd')

        self.joke = QPushButton(self)
        self.joke.setGeometry(QRect(160, 310, 91, 31))
        self.joke.setCursor(QCursor(Qt.PointingHandCursor))
        self.joke.setText('Joke Please!!')

        self.music = QPushButton(self)
        self.music.setGeometry(QRect(290, 260, 91, 31))
        self.music.setCursor(QCursor(Qt.PointingHandCursor))
        self.music.setText('Music')

        self.youtube = QPushButton(self)
        self.youtube.setGeometry(QRect(290, 310, 91, 31))
        self.youtube.setCursor(QCursor(Qt.PointingHandCursor))
        self.youtube.setText('Youtube')

        self.time = QPushButton(self)
        self.time.setGeometry(QRect(20, 310, 91, 31))
        self.time.setCursor(QCursor(Qt.PointingHandCursor))
        self.time.setText('Tell Time')

        self.weather = QPushButton(self)
        self.weather.setGeometry(QRect(420, 310, 91, 31))
        self.weather.setCursor(QCursor(Qt.PointingHandCursor))
        self.weather.setText('Weather')

        self.calculator = QPushButton(self)
        self.calculator.setGeometry(QRect(550, 260, 101, 31))
        self.calculator.setCursor(QCursor(Qt.PointingHandCursor))
        self.calculator.setText('Calculator')

        self.wikipedia = QPushButton(self)
        self.wikipedia.setGeometry(QRect(550, 310, 101, 31))
        self.wikipedia.setCursor(QCursor(Qt.PointingHandCursor))
        self.wikipedia.setText('India Wikipedia')

        self.news = QPushButton(self)
        self.news.setGeometry(QRect(20, 360, 91, 31))
        self.news.setCursor(QCursor(Qt.PointingHandCursor))
        self.news.setText('Latest News')

        self.meaning = QPushButton(self)
        self.meaning.setGeometry(QRect(420, 360, 231, 31))
        self.meaning.setCursor(QCursor(Qt.PointingHandCursor))
        self.meaning.setText('Meaning of Obsolete (or any word)')

        self.harry_potter = QPushButton(self)
        self.harry_potter.setGeometry(QRect(290, 360, 91, 31))
        self.harry_potter.setCursor(QCursor(Qt.PointingHandCursor))
        self.harry_potter.setText('Harry Potter')

        self.translate = QPushButton(self)
        self.translate.setGeometry(QRect(160, 360, 91, 31))
        self.translate.setCursor(QCursor(Qt.PointingHandCursor))
        self.translate.setText('Open Translate')

        self.line = QFrame(self)
        self.line.setGeometry(QRect(20, 200, 661, 16))
        self.line.setFrameShape(QFrame.HLine)
        self.line.setFrameShadow(QFrame.Sunken)

        self.label = QLabel(self)
        self.label.setGeometry(QRect(20, 100, 631, 91))
        self.label.setFont(QFont('Roboto', 12))
        self.label.setTextFormat(Qt.AutoText)
        self.label.setWordWrap(True)

        self.wish()

        # Making the Widgets Functional
        self.query.returnPressed.connect(lambda: self.on_enter())
        self.query.returnPressed.connect(lambda: self.clear_text())

        self.update.clicked.connect(lambda: self.update_func())
        self.music.clicked.connect(lambda: self.music_func())
        self.games.clicked.connect(lambda: self.games_func())
        self.calculator.clicked.connect(lambda: self.calculator_func())
        self.weather.clicked.connect(lambda: self.weather_func())
        self.news.clicked.connect(lambda: self.news_func())
        self.translate.clicked.connect(lambda: self.translate_func())
        self.time.clicked.connect(lambda: self.time_func())
        self.joke.clicked.connect(lambda: self.joke_func())
        self.youtube.clicked.connect(lambda: self.youtube_func())
        self.wikipedia.clicked.connect(lambda: self.wikipedia_func())
        self.chrome.clicked.connect(lambda: self.chrome_func())
        self.cmd.clicked.connect(lambda: self.cmd_func())
        self.meaning.clicked.connect(lambda: self.meaning_func())
        self.harry_potter.clicked.connect(lambda: self.potter_func())

    def pronunciator_func(self):
        self.speak('Opening Pronunciator')
        from pronunciator import Pronunciator
        self.pronunciator_win = Pronunciator()
        self.pronunciator_win.show()

    def pong_func(self):
        import pong

    def notepad_func(self):
        self.speak('Opening Notepad')
        from notepad import Notepad
        self.notepad_win = Notepad()
        self.notepad_win.show()

    def update_func(self):
        os.startfile('Each Version Updates.txt')

    def translate_func(self):
        self.speak(
            'Opening Translate\nPlease Wait as opening Translate may take up to 4-5 seconds'
        )
        from translate import Translate
        self.translate_win = Translate()
        self.translate_win.show()

    def games_func(self):
        self.speak('Opening GameHub')
        from games import GameHub
        self.game_win = GameHub()
        self.game_win.show()

    def weather_func(self):
        self.speak('Opening Weather.')
        from weather import Weather
        self.weather_win = Weather()
        self.weather_win.show()

    def music_func(self):
        self.speak('Opening Muse')
        from music import Music
        self.music_win = Music()
        self.music_win.show()

    def calculator_func(self):
        self.speak('Opening Calculator.')
        from calculator import Calculator
        self.calculator_win = Calculator()
        self.calculator_win.show()

    def news_func(self):
        self.speak('Opening News.')
        from news import News
        self.news_win = News()
        self.news_win.show()
        self.speak(
            'Welcome to News.\nThese are the latest international headlines according to BBC News Network.'
        )

    def chrome_func(self):
        try:
            chrome_path = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
            os.startfile(chrome_path)
            self.speak('Opening Chrome.')
        except Exception:
            self.speak(
                'No Google Chrome installation found on the host device.')

    def cmd_func(self):
        cmd_path = 'C:\\Windows\\system32\\cmd.exe'
        os.startfile(cmd_path)
        self.speak('Opening Command Prompt.')

    def time_func(self):
        question = 'time'
        app_id = 'LLQ4QY-A7K3LEL4T8'
        client = wolframalpha.Client(app_id)
        res = client.query(question)
        answer = next(res.results).text
        self.speak(answer)

    def joke_func(self):
        self.speak(pyjokes.get_joke())

    def youtube_func(self):
        webbrowser.open('https://www.youtube.com')
        self.speak('Opening Youtube.')

    def wikipedia_func(self):
        try:
            self.speak('Searching Wikipedia. Please Wait...')
            query = 'India'.replace('wikipedia', '')
            result = wikipedia.summary(query, sentences=1)
            self.speak('According to Wikipedia...')
            self.speak(result)
        except Exception as e:
            self.speak(e)

    def meaning_func(self):
        question = 'obsolete'
        app_id = 'LLQ4QY-A7K3LEL4T8'
        client = wolframalpha.Client(app_id)
        res = client.query(question)
        answer = next(res.results).text
        self.speak(answer)

    def potter_func(self):
        new = 2
        google_url = "http://google.com/?#q="
        webbrowser.open(google_url + 'Harry Potter', new=new)

    def clear_text(self):
        self.query.clear()

    def on_enter(self):
        user_query = self.query.text().lower()

        if 'wikipedia' in user_query:
            try:
                self.speak('Searching Wikipedia. Please Wait...')
                user_query = user_query.replace('wikipedia', '')
                result = wikipedia.summary(user_query, sentences=1)
                self.speak('According to Wikipedia...')
                self.speak(result)
            except Exception as e:
                self.speak('Please try again later.')
                self.speak(e)

        elif 'youtube' in user_query:
            webbrowser.open('https://www.youtube.com')
            self.speak('Opening Youtube.')

        elif 'google' in user_query:
            webbrowser.open('https://www.google.com/')
            self.speak('Opening Google.')

        elif 'chrome' in user_query:  # You'll have to download google chrome first on your desktop/pc.
            try:
                chrome_path = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
                os.startfile(chrome_path)
                self.speak('Opening Chrome')
            except Exception:
                self.speak(
                    'No Google Chrome installation found on the host device.')

        elif 'cmd' in user_query:
            cmd_path = 'C:\\Windows\\system32\\cmd.exe'
            os.startfile(cmd_path)
            self.speak('Opening Command Prompt.')

        elif 'control panel' in user_query:

            cp_path = 'C:\\Windows\\system32\\control.exe'
            os.startfile(cp_path)
            self.speak('Opening Control Panel.')

        elif 'bye' in user_query or 'goodbye' in user_query or 'good night' in user_query or 'see you later' in user_query:
            self.speak(random.choice(self.bye))
            sys.exit()

        elif 'hello' in user_query or 'hi' in user_query:
            self.speak(random.choice(self.hello))

        elif 'joke' in user_query:
            self.speak(pyjokes.get_joke())

        elif 'who are you' in user_query:
            self.speak('I am Artigence, your artificial intelligence.')

        elif 'map' in user_query or 'maps' in user_query:
            self.speak('Opening Google Maps.')
            webbrowser.open("https://www.google.com/maps")

        elif 'open calculator' in user_query or 'calculator' in user_query:
            self.calculator_func()

        elif 'news' in user_query:
            self.news_func()
            self.speak(
                'Welcome to News.\nThese are the latest international headlines according to BBC News Network.'
            )

        elif 'weather' in user_query:
            self.weather_func()

        elif 'games' in user_query:
            self.games_func()

        elif 'pronunciator' in user_query or 'pronounce' in user_query:
            self.pronunciator_func()

        elif 'translate' in user_query:
            self.translate_func()

        elif 'music' in user_query:
            self.music_func()

        elif 'notepad' in user_query:
            self.notepad_func()

        else:
            try:
                question = user_query
                app_id = 'LLQ4QY-A7K3LEL4T8'
                client = wolframalpha.Client(app_id)
                res = client.query(question)
                answer = next(res.results).text
                self.label.setText(answer)
                self.label.adjustSize()

            except:
                new = 2
                google_url = "http://google.com/?#q="
                query = user_query
                webbrowser.open(google_url + query, new=new)

    # The A.I. will speak through this function
    def speak(self, audio):
        self.engine = pyttsx3.init('sapi5')
        voices = self.engine.getProperty('voices')
        self.engine.setProperty('voice', voices[1].id)
        self.engine.setProperty('rate', 165)
        self.label.setText(audio)
        self.engine.say(audio)
        self.engine.runAndWait()
        self.label.clear()

    def wish(self):
        hour = int(datetime.now().hour)
        if 0 <= hour < 12:
            self.speak('Good Morning.')
        elif 12 <= hour < 18:
            self.speak('Good Afternoon.')
        else:
            self.speak('Good Evening.')

        self.speak('I am Artigence.')
        self.speak('How may I help you today')

    hello = ['Kon\'nichiwa', 'Ciao', 'Hola', 'Bonjour', 'Hello', 'Hi', 'Hiya']
    bye = [
        'Adios', 'Goodbye', 'Bye-Bye', 'See you next time.', 'Artigence Out.',
        'It was nice talking to you sir. Have a nice day.'
    ]

    def dark(self):
        self.setPalette(self.palette)

    def light(self):
        self.setPalette(self.light_palette)
class FilterWidgetBase(QWidget):
    """Filter widget class."""

    okPressed = Signal()
    cancelPressed = Signal()

    def __init__(self, parent):
        """Init class.

        Args:
            parent (QWidget)
        """
        super().__init__(parent)
        # parameters
        self._filter_state = set()
        self._filter_empty_state = None
        self._search_text = ''
        self.search_delay = 200

        # create ui elements
        self._ui_vertical_layout = QVBoxLayout(self)
        self._ui_list = QListView()
        self._ui_edit = QLineEdit()
        self._ui_edit.setPlaceholderText('Search')
        self._ui_edit.setClearButtonEnabled(True)
        self._ui_buttons = QDialogButtonBox(QDialogButtonBox.Cancel
                                            | QDialogButtonBox.Ok)
        self._ui_vertical_layout.addWidget(self._ui_edit)
        self._ui_vertical_layout.addWidget(self._ui_list)
        self._ui_vertical_layout.addWidget(self._ui_buttons)

        # add models
        self._search_timer = QTimer(
        )  # Used to limit search so it doesn't search when typing
        self._search_timer.setSingleShot(True)

        self._filter_model = None

    def connect_signals(self):
        self._ui_list.clicked.connect(self._filter_model._handle_index_clicked)
        self._search_timer.timeout.connect(self._filter_list)
        self._ui_edit.textChanged.connect(self._text_edited)
        self._ui_buttons.button(QDialogButtonBox.Ok).clicked.connect(
            self._apply_filter)
        self._ui_buttons.button(QDialogButtonBox.Cancel).clicked.connect(
            self._cancel_filter)

    def save_state(self):
        """Saves the state of the FilterCheckboxListModel."""
        self._filter_state = self._filter_model.get_selected()
        if self._filter_model._show_empty:
            self._filter_empty_state = self._filter_model._empty_selected

    def reset_state(self):
        """Sets the state of the FilterCheckboxListModel to saved state."""
        self._filter_model.set_selected(self._filter_state,
                                        self._filter_empty_state)

    def clear_filter(self):
        """Selects all items in FilterCheckBoxListModel."""
        self._filter_model.reset_selection()
        self.save_state()

    def has_filter(self):
        """Returns true if any item is filtered in FilterCheckboxListModel false otherwise."""
        return not self._filter_model._all_selected

    def set_filter_list(self, data):
        """Sets the list of items to filter."""
        self._filter_state = list(data)
        self._filter_model.set_list(self._filter_state)

    def _apply_filter(self):
        """Apply current filter and save state."""
        self._filter_model.apply_filter()
        self.save_state()
        self._ui_edit.setText('')
        self.okPressed.emit()

    def _cancel_filter(self):
        """Cancel current edit of filter and set the state to the stored state."""
        self._filter_model.remove_filter()
        self.reset_state()
        self._ui_edit.setText('')
        self.cancelPressed.emit()

    def _filter_list(self):
        """Filter list with current text."""
        self._filter_model.set_filter(self._search_text)

    def _text_edited(self, new_text):
        """Callback for edit text, starts/restarts timer.
        Start timer after text is edited, restart timer if text
        is edited before last time out.
        """
        self._search_text = new_text
        self._search_timer.start(self.search_delay)
class Pronunciator(QMainWindow):
    def __init__(self):
        super(Pronunciator, self).__init__()
        self.setMaximumHeight(21)
        self.setMinimumWidth(200)
        self.setWindowTitle('Pronunciator')
        self.setWindowIcon(QIcon('arti.PNG'))

        palette = QPalette()
        palette.setColor(palette.Window, QColor('#000000'))
        palette.setColor(palette.WindowText, QColor('#FFFFFF'))
        self.setPalette(palette)

        centralWidget = QWidget()
        self.setCentralWidget(centralWidget)
        layout = QFormLayout(centralWidget)

        textLayout = QHBoxLayout()

        self.text = QLineEdit()
        self.text.setClearButtonEnabled(True)

        textLayout.addWidget(self.text)

        self.sayButton = QPushButton('Say')
        textLayout.addWidget(self.sayButton)

        self.text.returnPressed.connect(self.sayButton.animateClick)
        self.sayButton.clicked.connect(self.say)
        layout.addRow('Text:', textLayout)

        self.voiceCombo = QComboBox()
        layout.addRow('Voice:', self.voiceCombo)

        self.volumeSlider = QSlider(Qt.Horizontal)
        self.volumeSlider.setMinimum(0)
        self.volumeSlider.setMaximum(100)
        self.volumeSlider.setValue(100)
        layout.addRow('Volume:', self.volumeSlider)

        self.engine = None
        engineNames = QTextToSpeech.availableEngines()
        if len(engineNames) > 0:
            engineName = engineNames[0]
            self.engine = QTextToSpeech(engineName)
            self.engine.stateChanged.connect(self.stateChanged)

            self.voices = []
            for voice in self.engine.availableVoices():
                self.voices.append(voice)
                self.voiceCombo.addItem(voice.name())
        else:
            self.setWindowTitle('No voices available')
            self.sayButton.setEnabled(False)

    def say(self):
        self.sayButton.setEnabled(False)
        self.engine.setVoice(self.voices[self.voiceCombo.currentIndex()])
        self.engine.setVolume(float(self.volumeSlider.value()) / 100)
        self.engine.say(self.text.text())

    def stateChanged(self, state):
        if state == QTextToSpeech.State.Ready:
            self.sayButton.setEnabled(True)
Ejemplo n.º 12
0
class MainWindow(QMainWindow):
    """Provides the parent window that includes the BookmarkWidget,
    BrowserTabWidget, and a DownloadWidget, to offer the complete
    web browsing experience."""
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('PySide2 tabbed browser Example')

        self._tab_widget = BrowserTabWidget(create_main_window_with_browser)
        self._tab_widget.enabled_changed.connect(self._enabled_changed)
        self._tab_widget.download_requested.connect(self._download_requested)
        self.setCentralWidget(self._tab_widget)
        self.connect(self._tab_widget, QtCore.SIGNAL("url_changed(QUrl)"),
                     self.url_changed)

        self._bookmark_dock = QDockWidget()
        self._bookmark_dock.setWindowTitle('Bookmarks')
        self._bookmark_widget = BookmarkWidget()
        self._bookmark_widget.open_bookmark.connect(self.load_url)
        self._bookmark_widget.open_bookmark_in_new_tab.connect(self.load_url_in_new_tab)
        self._bookmark_dock.setWidget(self._bookmark_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self._bookmark_dock)

        self._find_tool_bar = None

        self._actions = {}
        self._create_menu()

        self._tool_bar = QToolBar()
        self.addToolBar(self._tool_bar)
        for action in self._actions.values():
            if not action.icon().isNull():
                self._tool_bar.addAction(action)

        self._addres_line_edit = QLineEdit()
        self._addres_line_edit.setClearButtonEnabled(True)
        self._addres_line_edit.returnPressed.connect(self.load)
        self._tool_bar.addWidget(self._addres_line_edit)
        self._zoom_label = QLabel()
        self.statusBar().addPermanentWidget(self._zoom_label)
        self._update_zoom_label()

        self._bookmarksToolBar = QToolBar()
        self.addToolBar(Qt.TopToolBarArea, self._bookmarksToolBar)
        self.insertToolBarBreak(self._bookmarksToolBar)
        self._bookmark_widget.changed.connect(self._update_bookmarks)
        self._update_bookmarks()

    def _update_bookmarks(self):
        self._bookmark_widget.populate_tool_bar(self._bookmarksToolBar)
        self._bookmark_widget.populate_other(self._bookmark_menu, 3)

    def _create_menu(self):
        file_menu = self.menuBar().addMenu("&File")
        exit_action = QAction(QIcon.fromTheme("application-exit"), "E&xit",
                             self, shortcut = "Ctrl+Q", triggered=qApp.quit)
        file_menu.addAction(exit_action)

        navigation_menu = self.menuBar().addMenu("&Navigation")

        style_icons = ':/qt-project.org/styles/commonstyle/images/'
        back_action = QAction(QIcon.fromTheme("go-previous",
                                             QIcon(style_icons + 'left-32.png')),
                             "Back", self,
                             shortcut = QKeySequence(QKeySequence.Back),
                             triggered = self._tab_widget.back)
        self._actions[QWebEnginePage.Back] = back_action
        back_action.setEnabled(False)
        navigation_menu.addAction(back_action)
        forward_action = QAction(QIcon.fromTheme("go-next",
                                                QIcon(style_icons + 'right-32.png')),
                                "Forward", self,
                                shortcut = QKeySequence(QKeySequence.Forward),
                                triggered = self._tab_widget.forward)
        forward_action.setEnabled(False)
        self._actions[QWebEnginePage.Forward] = forward_action

        navigation_menu.addAction(forward_action)
        reload_action = QAction(QIcon(style_icons + 'refresh-32.png'),
                               "Reload", self,
                               shortcut = QKeySequence(QKeySequence.Refresh),
                               triggered = self._tab_widget.reload)
        self._actions[QWebEnginePage.Reload] = reload_action
        reload_action.setEnabled(False)
        navigation_menu.addAction(reload_action)

        navigation_menu.addSeparator()

        new_tab_action = QAction("New Tab", self,
                             shortcut = 'Ctrl+T',
                             triggered = self.add_browser_tab)
        navigation_menu.addAction(new_tab_action)

        close_tab_action = QAction("Close Current Tab", self,
                                 shortcut = "Ctrl+W",
                                 triggered = self._close_current_tab)
        navigation_menu.addAction(close_tab_action)

        edit_menu = self.menuBar().addMenu("&Edit")

        find_action = QAction("Find", self,
                             shortcut = QKeySequence(QKeySequence.Find),
                             triggered = self._show_find)
        edit_menu.addAction(find_action)

        edit_menu.addSeparator()
        undo_action = QAction("Undo", self,
                             shortcut = QKeySequence(QKeySequence.Undo),
                             triggered = self._tab_widget.undo)
        self._actions[QWebEnginePage.Undo] = undo_action
        undo_action.setEnabled(False)
        edit_menu.addAction(undo_action)

        redo_action = QAction("Redo", self,
                             shortcut = QKeySequence(QKeySequence.Redo),
                             triggered = self._tab_widget.redo)
        self._actions[QWebEnginePage.Redo] = redo_action
        redo_action.setEnabled(False)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction("Cut", self,
                            shortcut = QKeySequence(QKeySequence.Cut),
                            triggered = self._tab_widget.cut)
        self._actions[QWebEnginePage.Cut] = cut_action
        cut_action.setEnabled(False)
        edit_menu.addAction(cut_action)

        copy_action = QAction("Copy", self,
                             shortcut = QKeySequence(QKeySequence.Copy),
                             triggered = self._tab_widget.copy)
        self._actions[QWebEnginePage.Copy] = copy_action
        copy_action.setEnabled(False)
        edit_menu.addAction(copy_action)

        paste_action = QAction("Paste", self,
                             shortcut = QKeySequence(QKeySequence.Paste),
                             triggered = self._tab_widget.paste)
        self._actions[QWebEnginePage.Paste] = paste_action
        paste_action.setEnabled(False)
        edit_menu.addAction(paste_action)

        edit_menu.addSeparator()

        select_all_action = QAction("Select All", self,
                                  shortcut = QKeySequence(QKeySequence.SelectAll),
                                  triggered = self._tab_widget.select_all)
        self._actions[QWebEnginePage.SelectAll] = select_all_action
        select_all_action.setEnabled(False)
        edit_menu.addAction(select_all_action)

        self._bookmark_menu = self.menuBar().addMenu("&Bookmarks")
        add_bookmark_action = QAction("&Add Bookmark", self,
                                    triggered = self._add_bookmark)
        self._bookmark_menu.addAction(add_bookmark_action)
        add_tool_bar_bookmark_action = QAction("&Add Bookmark to Tool Bar", self,
                                           triggered = self._add_tool_bar_bookmark)
        self._bookmark_menu.addAction(add_tool_bar_bookmark_action)
        self._bookmark_menu.addSeparator()

        tools_menu = self.menuBar().addMenu("&Tools")
        download_action = QAction("Open Downloads", self,
                                 triggered = DownloadWidget.open_download_directory)
        tools_menu.addAction(download_action)

        window_menu = self.menuBar().addMenu("&Window")

        window_menu.addAction(self._bookmark_dock.toggleViewAction())

        window_menu.addSeparator()

        zoom_in_action = QAction(QIcon.fromTheme("zoom-in"),
                               "Zoom In", self,
                               shortcut = QKeySequence(QKeySequence.ZoomIn),
                               triggered = self._zoom_in)
        window_menu.addAction(zoom_in_action)
        zoom_out_action = QAction(QIcon.fromTheme("zoom-out"),
                                "Zoom Out", self,
                                shortcut = QKeySequence(QKeySequence.ZoomOut),
                                triggered = self._zoom_out)
        window_menu.addAction(zoom_out_action)

        reset_zoom_action = QAction(QIcon.fromTheme("zoom-original"),
                                  "Reset Zoom", self,
                                  shortcut = "Ctrl+0",
                                  triggered = self._reset_zoom)
        window_menu.addAction(reset_zoom_action)

        about_menu = self.menuBar().addMenu("&About")
        about_action = QAction("About Qt", self,
                              shortcut = QKeySequence(QKeySequence.HelpContents),
                              triggered=qApp.aboutQt)
        about_menu.addAction(about_action)

    def add_browser_tab(self):
        return self._tab_widget.add_browser_tab()

    def _close_current_tab(self):
        if self._tab_widget.count() > 1:
            self._tab_widget.close_current_tab()
        else:
            self.close()

    def close_event(self, event):
        main_windows.remove(self)
        event.accept()

    def load(self):
        url_string = self._addres_line_edit.text().strip()
        if url_string:
            self.load_url_string(url_string)

    def load_url_string(self, url_s):
        url = QUrl.fromUserInput(url_s)
        if (url.isValid()):
            self.load_url(url)

    def load_url(self, url):
        self._tab_widget.load(url)

    def load_url_in_new_tab(self, url):
        self.add_browser_tab().load(url)

    def url_changed(self, url):
        self._addres_line_edit.setText(url.toString())

    def _enabled_changed(self, web_action, enabled):
        action = self._actions[web_action]
        if action:
            action.setEnabled(enabled)

    def _add_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_bookmark(url, title, icon)

    def _add_tool_bar_bookmark(self):
        index = self._tab_widget.currentIndex()
        if index >= 0:
            url = self._tab_widget.url()
            title = self._tab_widget.tabText(index)
            icon = self._tab_widget.tabIcon(index)
            self._bookmark_widget.add_tool_bar_bookmark(url, title, icon)

    def _zoom_in(self):
        new_zoom = self._tab_widget.zoom_factor() * 1.5
        if (new_zoom <= WebEngineView.maximum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _zoom_out(self):
        new_zoom = self._tab_widget.zoom_factor() / 1.5
        if (new_zoom >= WebEngineView.minimum_zoom_factor()):
            self._tab_widget.set_zoom_factor(new_zoom)
            self._update_zoom_label()

    def _reset_zoom(self):
        self._tab_widget.set_zoom_factor(1)
        self._update_zoom_label()

    def _update_zoom_label(self):
        percent = int(self._tab_widget.zoom_factor() * 100)
        self._zoom_label.setText("{}%".format(percent))

    def _download_requested(self, item):
        # Remove old downloads before opening a new one
        for old_download in self.statusBar().children():
            if type(old_download).__name__ == 'download_widget' and \
                old_download.state() != QWebEngineDownloadItem.DownloadInProgress:
                self.statusBar().removeWidget(old_download)
                del old_download

        item.accept()
        download_widget = download_widget(item)
        download_widget.removeRequested.connect(self._remove_download_requested,
                                               Qt.QueuedConnection)
        self.statusBar().addWidget(download_widget)

    def _remove_download_requested(self):
            download_widget = self.sender()
            self.statusBar().removeWidget(download_widget)
            del download_widget

    def _show_find(self):
        if self._find_tool_bar is None:
            self._find_tool_bar = FindToolBar()
            self._find_tool_bar.find.connect(self._tab_widget.find)
            self.addToolBar(Qt.BottomToolBarArea, self._find_tool_bar)
        else:
            self._find_tool_bar.show()
        self._find_tool_bar.focus_find()

    def write_bookmarks(self):
        self._bookmark_widget.write_bookmarks()
Ejemplo n.º 13
0
class TestRunner(ToolInstance):
    def __init__(self, session, name):
        super().__init__(session, name)
        self.tool_window = MainToolWindow(self)

        self._build_ui()

    def _build_ui(self):
        """
        ui should have:
            * table with a list of available tests and show results after they are done
            * way to filter tests
            * button to run tests
        """
        layout = QVBoxLayout()

        # table to list test classes and the results
        self.table = QTableWidget()
        self.table.setColumnCount(2)
        self.table.setHorizontalHeaderLabels(["test", "result"])
        self.table.horizontalHeader().setSectionResizeMode(
            0,
            self.table.horizontalHeader().Interactive)
        self.table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.table.horizontalHeader().setSectionResizeMode(
            1,
            self.table.horizontalHeader().Stretch)
        self.table.setSizePolicy(QSizePolicy.MinimumExpanding,
                                 QSizePolicy.MinimumExpanding)
        self.table.setSelectionBehavior(self.table.SelectRows)
        layout.insertWidget(0, self.table, 1)

        self.filter = QLineEdit()
        self.filter.setPlaceholderText("filter test names")
        self.filter.setClearButtonEnabled(True)
        self.filter.textChanged.connect(self.apply_filter)
        layout.insertWidget(1, self.filter, 0)

        self.run_button = QPushButton("run tests")
        self.run_button.clicked.connect(self.run_tests)
        self.run_button.setToolTip(
            "if no tests are selected on the table, run all tests\n" +
            "otherwise, run selected tests")
        layout.insertWidget(2, self.run_button)

        self.fill_table()
        self.table.resizeColumnToContents(0)

        self.tool_window.ui_area.setLayout(layout)

        self.tool_window.manage(None)

    def apply_filter(self, text=None):
        """filter table to only show tests matching text"""
        if text is None:
            text = self.filter.text()

        if text:
            text = text.replace("(", "\(")
            text = text.replace(")", "\)")
            m = QRegularExpression(text)
            m.setPatternOptions(QRegularExpression.CaseInsensitiveOption)
            if m.isValid():
                m.optimize()
                filter = lambda row_num: m.match(
                    self.table.item(row_num, 0).text()).hasMatch()
            else:
                return

        else:
            filter = lambda row: True

        for i in range(0, self.table.rowCount()):
            self.table.setRowHidden(i, not filter(i))

    def fill_table(self):
        """adds test names to the table"""
        mgr = self.session.test_manager

        for name in mgr.tests.keys():
            row = self.table.rowCount()
            self.table.insertRow(row)
            test_name = QTableWidgetItem()
            test_name.setData(Qt.DisplayRole, name)
            self.table.setItem(row, 0, test_name)

    def run_tests(self):
        """run the tests selected on the table and show the results"""
        from TestManager.commands.test import test

        test_list = []

        use_selected = True
        for row in self.table.selectionModel().selectedRows():
            if self.table.isRowHidden(row.row()):
                continue

            test_name = self.table.item(row.row(), 0).text()
            test_list.append(test_name)

        if not test_list:
            use_selected = False
            for i in range(0, self.table.rowCount()):
                if self.table.isRowHidden(i):
                    continue

                test_name = self.table.item(i, 0).text()
                test_list.append(test_name)

            if not test_list:
                test_list = ["all"]

        results = test(self.session, test_list)

        cell_widgets = []

        for name in results:
            widget = QWidget()
            widget_layout = QHBoxLayout(widget)
            widget_layout.setContentsMargins(0, 0, 0, 0)

            success_button = get_button("success")
            fail_button = get_button("fail")
            skip_button = get_button("skip")
            error_button = get_button("error")
            expected_fail_button = get_button("expected fail")
            unexpected_success_button = get_button("unexpected success")

            success_count = 0
            fail_count = 0
            error_count = 0
            unexpected_success_count = 0
            expected_fail_count = 0
            skip_count = 0

            success_tooltip = "Successes:\n"
            fail_tooltip = "Failed tests:\n"
            error_tooltip = "Errors during test:\n"
            unexpected_success_tooltip = "Unexpected successes:\n"
            expected_fail_tooltip = "Expected fails:\n"
            skip_tooltip = "Skipped tests:\n"

            for case in results[name]:
                result, msg = results[name][case]
                if result == "success":
                    success_count += 1
                    success_tooltip += "%s.%s: %s\n" % (
                        case.__class__.__qualname__, case._testMethodName, msg)

                elif result == "fail":
                    fail_count += 1
                    fail_tooltip += "%s.%s failed: %s\n" % (
                        case.__class__.__qualname__, case._testMethodName, msg)

                elif result == "error":
                    error_count += 1
                    error_tooltip += "error during %s.%s: %s\n" % (
                        case.__class__.__qualname__, case._testMethodName, msg)

                elif result == "expected_failure":
                    expected_fail_count += 1
                    expected_fail_tooltip += "intended failure during %s.%s: %s\n" % (
                        case.__class__.__qualname__, case._testMethodName, msg)

                elif result == "skip":
                    skip_count += 1
                    skip_tooltip += "%s.%s\n" % (case.__class__.__qualname__,
                                                 case._testMethodName)

                elif result == "unexpected_success":
                    unexpected_success_count += 1
                    unexpected_success_tooltip += "%s.%s should not have worked, but did\n" % (
                        case.__class__.__qualname__, case._testMethodName)

            success_tooltip = success_tooltip.strip()
            fail_tooltip = fail_tooltip.strip()
            error_tooltip = error_tooltip.strip()
            expected_fail_tooltip = expected_fail_tooltip.strip()
            skip_tooltip = skip_tooltip.strip()
            unexpected_success_tooltip = unexpected_success_tooltip.strip()

            icon_count = 0
            if success_count:
                success_button.setText("%i" % success_count)
                success_button.setToolTip(success_tooltip)
                success_button.clicked.connect(
                    lambda *args, t_name=name, res=success_tooltip: self.
                    tool_window.create_child_window(
                        "successes for %s" % t_name,
                        text=res,
                        window_class=ResultsWindow,
                    ))
                widget_layout.insertWidget(icon_count, success_button, 1)
                icon_count += 1

            if fail_count:
                fail_button.setText("%i" % fail_count)
                fail_button.setToolTip(fail_tooltip)
                fail_button.clicked.connect(
                    lambda *args, res=fail_tooltip: self.tool_window.
                    create_child_window(
                        "failures for %s" % name,
                        text=res,
                        window_class=ResultsWindow,
                    ))
                widget_layout.insertWidget(icon_count, fail_button, 1)
                icon_count += 1

            if error_count:
                error_button.setText("%i" % error_count)
                error_button.setToolTip(error_tooltip)
                error_button.clicked.connect(
                    lambda *args, res=error_tooltip: self.tool_window.
                    create_child_window(
                        "errors for %s" % name,
                        text=res,
                        window_class=ResultsWindow,
                    ))
                widget_layout.insertWidget(icon_count, error_button, 1)
                icon_count += 1

            if unexpected_success_count:
                unexpected_success_button.setText("%i" %
                                                  unexpected_success_count)
                unexpected_success_button.setToolTip(
                    unexpected_success_tooltip)
                unexpected_success_button.clicked.connect(
                    lambda *args, res=unexpected_success_tooltip: self.
                    tool_window.create_child_window(
                        "unexpected successes for %s" % name,
                        text=res,
                        window_class=ResultsWindow,
                    ))
                widget_layout.insertWidget(icon_count,
                                           unexpected_success_button, 1)
                icon_count += 1

            if expected_fail_count:
                expected_fail_button.setText("%i" % expected_fail_count)
                expected_fail_button.setToolTip(expected_fail_tooltip)
                expected_fail_button.clicked.connect(
                    lambda *args, res=expected_fail_tooltip: self.tool_window.
                    create_child_window(
                        "expected failures for %s" % name,
                        text=res,
                        window_class=ResultsWindow,
                    ))
                widget_layout.insertWidget(icon_count, expected_fail_button, 1)
                icon_count += 1

            if skip_count:
                skip_button.setText("%i" % skip_count)
                skip_button.setToolTip(skip_tooltip)
                skip_button.clicked.connect(
                    lambda *args, res=skip_tooltip: self.tool_window.
                    create_child_window(
                        "skipped tests for %s" % name,
                        text=res,
                        window_class=ResultsWindow,
                    ))
                widget_layout.insertWidget(icon_count, skip_button, 1)

            cell_widgets.append(widget)

        widget_count = 0
        if use_selected:
            for row in self.table.selectionModel().selectedRows():
                if self.table.isRowHidden(row.row()):
                    continue

                self.table.setCellWidget(row.row(), 1,
                                         cell_widgets[widget_count])
                self.table.resizeRowToContents(row.row())
                widget_count += 1

        else:
            for i in range(0, self.table.rowCount()):
                if self.table.isRowHidden(i):
                    continue

                self.table.setCellWidget(i, 1, cell_widgets[widget_count])
                # self.table.resizeRowToContents(i)
                widget_count += 1
Ejemplo n.º 14
0
class ConnectDatabase(QDialog):
    def __init__(self, parent):
        super().__init__(parent)
        
        self.setWindowTitle("Connect Database")

        self.user_label = QLabel("Database User:"******"e.g. root")
        self.user.setDragEnabled(True)
        self.user.setFocus()
        self.user.setClearButtonEnabled(True)

        self.pw_label = QLabel("Database Password:"******"e.g. toor")
        self.password.setClearButtonEnabled(True)
        self.password.setEchoMode(QLineEdit.Password)

        self.db_name_label = QLabel("Database Name:")
        self.db_name = QLineEdit()
        self.db_name.setPlaceholderText("e.g. bank-db")
        self.db_name.setDragEnabled(True)
        self.db_name.setClearButtonEnabled(True)

        self.host_name_label = QLabel("Host Name:")
        self.host_name = QLineEdit()
        self.host_name.setPlaceholderText("e.g. localhost")
        self.host_name.setDragEnabled(True)
        self.host_name.setClearButtonEnabled(True)
        
        self.connect_bttn = QPushButton("Connect")
        self.connect_bttn.clicked.connect(self.connect)

        layout = QGridLayout()
        
        layout.addWidget(self.user_label, 0, 0)
        layout.addWidget(self.user, 0, 1)

        layout.addWidget(self.pw_label, 1, 0)
        layout.addWidget(self.password, 1, 1)

        layout.addWidget(self.db_name_label, 2, 0)
        layout.addWidget(self.db_name, 2, 1)

        layout.addWidget(self.host_name_label, 3, 0)
        layout.addWidget(self.host_name, 3, 1)

        layout.addWidget(self.connect_bttn, 4, 1)

        self.setLayout(layout)
        self.setModal(True)

    def connect(self):
        if os.path.exists("model/session/connected_dbs"):
            with open("model/session/connected_dbs", "rb") as sessions:
                db_sessions = pickle.load(sessions)
        else:
            db_sessions = []

        is_connected = False
        
        for db in db_sessions:
            if db["db"] == self.db_name.text():
                is_connected = True
                QMessageBox.critical(self, "Database Already Connected", "Database with the same name is already connected.", QMessageBox.Close)
                break

        if not is_connected:
            if len(self.user.text()) > 0 and len(self.password.text()) > 0 and len(self.db_name.text()) > 0 and len(self.host_name.text()) > 0:
                try:
                    connection = mysql.connect(
                        host=self.host_name.text(),
                        user=self.user.text(),
                        password=self.password.text(),
                        db=self.db_name.text(),
                        charset="utf8mb4",
                        cursorclass=mysql.cursors.DictCursor
                    )
                    try:
                        db_sessions.append(
                            {
                                "index": len(db_sessions) + 1,
                                "host": self.host_name.text(),
                                "user": self.user.text(),
                                "password": self.password.text(),
                                "db": self.db_name.text()
                            }
                        )

                        QMessageBox.information(self, "Database connected. You rock!", "Hooray! Database successfully connected with Zephyrus.\n\nHint: Press Ctrl+R to refresh databases", QMessageBox.Ok)

                        with open("model/session/connected_dbs", "wb") as sessions:
                            pickle.dump(db_sessions, sessions)

                        self.close()

                    except mysql.Error as e:
                        QMessageBox.critical(self, "Warning", "Incorrect database credentials, you might be bad at typing...", QMessageBox.Close)
                    finally:
                        connection.close()
                except RuntimeError as e:
                    QMessageBox.critical(self, "Connection Error", "There are no active MySQL servers!", QMessageBox.Close)
                except mysql.OperationalError as e:
                    QMessageBox.critical(self, "Connection Error", "Incorrect Credentials!", QMessageBox.Close)
            else:
                QMessageBox.critical(self, "Warning", "You didn't fill out all fields!", QMessageBox.Close)
Ejemplo n.º 15
0
class CommandWidget(TabWidgetExtension, QWidget):
    """Output for running queue"""

    # log state
    __log = False
    insertTextSignal = Signal(str, dict)
    updateCommandSignal = Signal(str)
    cliButtonsSateSignal = Signal(bool)
    cliValidateSignal = Signal(bool)
    resetSignal = Signal()

    def __init__(self, parent=None, proxyModel=None, controlQueue=None, log=None):
        super(CommandWidget, self).__init__(parent=parent, tabWidgetChild=self)

        self.__log = log
        self.__output = None
        self.__rename = None
        self.__tab = None

        # self.oCommand = MKVCommand()
        self.algorithm = None
        self.oCommand = MKVCommandParser()
        self.controlQueue = controlQueue
        self.parent = parent
        self.proxyModel = proxyModel
        self.model = proxyModel.sourceModel()
        self.outputWindow = QOutputTextWidget(self)
        self.log = log

        self._initControls()
        self._initUI()
        self._initHelper()

    def _initControls(self):
        #
        # command line
        #
        self.frmCmdLine = QFormLayout()
        btnPasteClipboard = QPushButtonWidget(
            Text.txt0164,
            function=lambda: qtRunFunctionInThread(self.pasteClipboard),
            margins="  ",
            toolTip=Text.txt0165,
        )
        self.cmdLine = QLineEdit()
        self.cmdLine.setValidator(
            ValidateCommand(self, self.cliValidateSignal, log=self.log)
        )
        self.frmCmdLine.addRow(btnPasteClipboard, self.cmdLine)
        self.frmCmdLine.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
        self.command = QWidget()
        self.command.setLayout(self.frmCmdLine)

        #
        # Button group definition
        #
        self.btnGroup = QGroupBox()
        self.btnGrid = QGridLayout()

        btnAddCommand = QPushButtonWidget(
            Text.txt0160,
            function=lambda: self.addCommand(JobStatus.Waiting),
            margins="  ",
            toolTip=Text.txt0161,
        )
        btnRename = QPushButtonWidget(
            Text.txt0182,
            function=self.parent.renameWidget.setAsCurrentTab,
            margins="  ",
            toolTip=Text.txt0183,
        )
        btnAddQueue = QPushButtonWidget(
            Text.txt0166,
            function=lambda: self.addCommand(JobStatus.AddToQueue),
            margins="  ",
            toolTip=Text.txt0167,
        )
        btnStartQueue = QPushButtonWidget(
            Text.txt0126,
            function=self.parent.jobsQueue.run,
            margins="  ",
            toolTip=Text.txt0169,
        )
        btnAnalysis = QPushButtonWidget(
            Text.txt0170,
            function=lambda: qtRunFunctionInThread(
                runAnalysis,
                command=self.cmdLine.text(),
                output=self.output,
                log=self.log,
            ),
            margins="  ",
            toolTip=Text.txt0171,
        )
        btnShowCommands = QPushButtonWidget(
            Text.txt0172,
            function=lambda: qtRunFunctionInThread(
                showCommands,
                output=self.output,
                command=self.cmdLine.text(),
                oCommand=self.oCommand,
                log=self.log,
            ),
            margins="  ",
            toolTip=Text.txt0173,
        )
        btnCheckFiles = QPushButtonWidget(
            Text.txt0174,
            function=lambda: qtRunFunctionInThread(
                checkFiles,
                output=self.output,
                command=self.cmdLine.text(),
                oCommand=self.oCommand,
                log=self.log,
            ),
            margins="  ",
            toolTip=Text.txt0175,
        )
        btnClear = QPushButtonWidget(
            Text.txt0176,
            function=self.clearOutputWindow,
            margins="  ",
            toolTip=Text.txt0177,
        )
        btnReset = QPushButtonWidget(
            Text.txt0178,
            function=self.reset,
            margins="  ",
            toolTip=Text.txt0179,
        )

        self.btnGrid.addWidget(btnAddCommand, 0, 0)
        self.btnGrid.addWidget(btnRename, 0, 1)
        self.btnGrid.addWidget(btnAddQueue, 1, 0)
        self.btnGrid.addWidget(btnStartQueue, 1, 1)
        self.btnGrid.addWidget(HorizontalLine(), 2, 0, 1, 2)
        self.btnGrid.addWidget(btnAnalysis, 3, 0)
        self.btnGrid.addWidget(btnShowCommands, 3, 1)
        self.btnGrid.addWidget(btnCheckFiles, 4, 0)
        self.btnGrid.addWidget(HorizontalLine(), 5, 0, 1, 2)
        self.btnGrid.addWidget(btnClear, 6, 0)
        self.btnGrid.addWidget(btnReset, 6, 1)
        self.btnGroup.setLayout(self.btnGrid)

        self.btnGroupBox = QGroupBox()
        self.btnHBox = QHBoxLayout()

        self.lblAlgorithm = QLabelWidget(
            Text.txt0094,
            textSuffix=":  ",
        )
        self.rbZero = QRadioButton("0", self)
        self.rbOne = QRadioButton("1", self)
        self.rbTwo = QRadioButton("2", self)

        btnDefaultAlgorithm = QPushButtonWidget(
            Text.txt0092,
            function=self.setDefaultAlgorithm,
            margins="  ",
            toolTip=Text.txt0093,
        )

        self.radioButtons = [self.rbZero, self.rbOne, self.rbTwo]

        self.btnHBox.addWidget(self.lblAlgorithm)
        self.btnHBox.addWidget(self.rbZero)
        self.btnHBox.addWidget(self.rbOne)
        self.btnHBox.addWidget(self.rbTwo)
        self.btnHBox.addWidget(btnDefaultAlgorithm)
        self.btnGroupBox.setLayout(self.btnHBox)

    def _initUI(self):

        grid = QGridLayout()
        grid.addWidget(self.command, 0, 0, 1, 2)
        grid.addWidget(self.btnGroupBox, 1, 0)
        grid.addWidget(self.btnGroup, 2, 0)
        grid.addWidget(self.outputWindow, 2, 1, 10, 1)

        self.setLayout(grid)

    def _initHelper(self):
        #
        # Signal interconnections
        #

        # local button state connect to related state
        self.parent.jobsQueue.addQueueItemSignal.connect(
            lambda: self.jobStartQueueState(True)
        )
        self.parent.jobsQueue.queueEmptiedSignal.connect(
            lambda: self.jobStartQueueState(False)
        )

        # job related
        self.parent.jobsQueue.runJobs.startSignal.connect(lambda: self.jobStatus(True))
        self.parent.jobsQueue.runJobs.finishedSignal.connect(
            lambda: self.jobStatus(False)
        )

        # map insertText signal to outputWidget one
        self.insertText = self.outputWindow.insertTextSignal

        # command
        self.updateCommandSignal.connect(self.updateCommand)
        self.cliButtonsSateSignal.connect(self.cliButtonsState)
        self.cliValidateSignal.connect(self.cliValidate)

        #
        # button state
        #

        # Command related
        # self.frmCmdLine.itemAt(0, QFormLayout.LabelRole).widget().setEnabled(False)
        self.cliButtonsState(False)
        self.btnGrid.itemAt(_Button.ANALYSIS).widget().setEnabled(False)

        # Clear buttons related
        self.btnGrid.itemAt(_Button.CLEAR).widget().setEnabled(False)
        self.btnGrid.itemAt(_Button.RESET).widget().setEnabled(False)

        # connect text windows textChanged to clearButtonState function
        self.outputWindow.textChanged.connect(self.clearButtonState)

        # connect command line textChanged to analysisButtonState function
        self.cmdLine.textChanged.connect(self.analysisButtonState)

        # Job Queue related
        self.btnGrid.itemAt(_Button.STARTQUEUE).widget().setEnabled(False)

        # Job Added to Queue
        self.parent.jobsQueue.addQueueItemSignal.connect(self.printJobIDAdded)

        #
        # Misc
        #
        self.cmdLine.setClearButtonEnabled(True)  # button at end of line to clear it

        # Algorithm radio buttons
        self.rbZero.toggled.connect(lambda: self.toggledRadioButton(self.rbZero))
        self.rbOne.toggled.connect(lambda: self.toggledRadioButton(self.rbOne))
        self.rbTwo.toggled.connect(lambda: self.toggledRadioButton(self.rbTwo))

        self.setDefaultAlgorithm()

    @classmethod
    def classLog(cls, setLogging=None):
        """
        get/set logging at class level
        every class instance will log
        unless overwritten

        Args:
            setLogging (bool):
                - True class will log
                - False turn off logging
                - None returns current Value

        Returns:
            bool:

            returns the current value set
        """

        if setLogging is not None:
            if isinstance(setLogging, bool):
                cls.__log = setLogging

        return cls.__log

    @property
    def log(self):
        """
        class property can be used to override the class global
        logging setting

        Returns:
            bool:

            True if logging is enable False otherwise
        """
        if self.__log is not None:
            return self.__log

        return CommandWidget.classLog()

    @log.setter
    def log(self, value):
        """set instance log variable"""

        if isinstance(value, bool) or value is None:
            self.__log = value
            # No variable used so for now use class log
            ValidateCommand.classLog(value)
            self.outputWindow.log = value

    @property
    def output(self):
        return self.__output

    @output.setter
    def output(self, value):
        self.__output = value

    @property
    def rename(self):
        return self.__rename

    @rename.setter
    def rename(self, value):
        if isinstance(value, object):
            self.__rename = value

    @Slot(list)
    def applyRename(self, renameFiles):

        if self.oCommand:
            self.oCommand.renameOutputFiles(renameFiles)

    @Slot(bool)
    def cliButtonsState(self, validateOK):
        """
        cliButtonsState change enabled status for buttons related with command line

        Args:
            validateOK (bool): True to enable, False to disable
        """

        for b in [
            _Button.ADDCOMMAND,
            _Button.RENAME,
            _Button.ADDQUEUE,
            _Button.SHOWCOMMANDS,
            _Button.CHECKFILES,
        ]:
            button = self.btnGrid.itemAt(b).widget()
            button.setEnabled(validateOK)

    @Slot(bool)
    def cliValidate(self, validateOK):
        """
        cliValidate Slot used by ValidateCommnad

        Args:
            validateOK (bool): True if command line is Ok.  False otherwise.
        """

        if validateOK:
            self.output.command.emit(
                "Command looks ok.\n", {LineOutput.AppendEnd: True}
            )
        else:
            if self.cmdLine.text() != "":
                self.output.command.emit("Bad command.\n", {LineOutput.AppendEnd: True})

        self.cliButtonsState(validateOK)
        self.updateObjCommnad(validateOK)

    @Slot(bool)
    def jobStartQueueState(self, state):

        if state and not isThreadRunning(config.WORKERTHREADNAME):
            self.btnGrid.itemAt(_Button.STARTQUEUE).widget().setEnabled(True)
        else:
            self.btnGrid.itemAt(_Button.STARTQUEUE).widget().setEnabled(False)

    @Slot(bool)
    def updateObjCommnad(self, valid):
        """Update the command object"""

        if valid:
            self.oCommand.command = self.cmdLine.text()
            if self.rename is not None:
                self.rename.setFilesSignal.emit(self.oCommand)
                self.rename.applyFileRenameSignal.connect(self.applyRename)
        else:
            self.oCommand.command = ""
            if self.rename is not None:
                self.rename.clear()

    @Slot(str)
    def updateCommand(self, command):
        """Update command input widget"""

        self.cmdLine.clear()
        self.cmdLine.setText(command)
        self.cmdLine.setCursorPosition(0)

    @Slot(int)
    def updateAlgorithm(self, algorithm):

        if 0 <= algorithm < len(self.radioButtons):
            self.radioButtons[algorithm].setChecked(True)

    @Slot(bool)
    def jobStatus(self, running):
        """
        jobStatus receive Signals for job start/end

        Args:
            running (bool): True if job started. False if ended.
        """

        if running:
            self.jobStartQueueState(False)
            palette = QPalette()
            color = checkColor(
                QColor(42, 130, 218), config.data.get(config.ConfigKey.DarkMode)
            )
            palette.setColor(QPalette.WindowText, color)
            self.parent.jobsLabel.setPalette(palette)
        else:
            palette = QPalette()
            color = checkColor(None, config.data.get(config.ConfigKey.DarkMode))
            palette.setColor(QPalette.WindowText, color)
            self.parent.jobsLabel.setPalette(palette)

    def addCommand(self, status):
        """
        addCommand add command row in jobs table

        Args:
            status (JobStatus): Status for job to be added should be either
                                JobStatus.Waiting or JobStatus.AddToQueue
        """

        totalJobs = self.model.rowCount()
        command = self.cmdLine.text()
        # [cell value, tooltip, obj]
        data = [
            ["", "", self.algorithm],
            [status, "Status code", None],
            [command, command, self.oCommand],
        ]
        self.model.insertRows(totalJobs, 1, data=data)
        self.cmdLine.clear()

    def analysisButtonState(self):
        """Set clear button state"""

        if self.cmdLine.text() != "":
            self.btnGrid.itemAt(_Button.ANALYSIS).widget().setEnabled(True)
        else:
            self.btnGrid.itemAt(_Button.ANALYSIS).widget().setEnabled(False)

    def clearButtonState(self):
        """Set clear button state"""

        if self.outputWindow.toPlainText() != "":
            self.btnGrid.itemAt(_Button.CLEAR).widget().setEnabled(True)
        else:
            self.btnGrid.itemAt(_Button.CLEAR).widget().setEnabled(False)

    def clearOutputWindow(self):
        """
        clearOutputWindow clear the command output window
        """

        language = config.data.get(config.ConfigKey.Language)
        bAnswer = False

        # Clear output window?
        title = "Clear output"
        msg = "¿" if language == "es" else ""
        msg += "Clear output window" + "?"
        bAnswer = yesNoDialog(self, msg, title)

        if bAnswer:
            self.outputWindow.clear()

    def printJobIDAdded(self, index):

        jobID = self.model.dataset[index.row(), index.column()]

        self.output.command.emit(
            f"Job: {jobID} added to Queue...\n", {LineOutput.AppendEnd: True}
        )

    def pasteClipboard(self):
        """Paste clipboard to command QLineEdit"""

        clip = QApplication.clipboard().text()

        if clip:
            self.output.command.emit(
                "Checking command...\n", {LineOutput.AppendEnd: True}
            )
            self.update()
            self.updateCommandSignal.emit(clip)

    def reset(self):
        """
        reset program status
        """

        language = config.data.get(config.ConfigKey.Language)

        if not isThreadRunning(config.WORKERTHREADNAME):

            language = config.data.get(config.ConfigKey.Language)
            bAnswer = False

            # Clear output window?
            title = "Reset"
            msg = "¿" if language == "es" else ""
            msg += "Reset Application" + "?"
            bAnswer = yesNoDialog(self, msg, title)

            if bAnswer:
                self.cmdLine.clear()
                self.outputWindow.clear()
                self.output.jobOutput.clear()
                self.output.errorOutput.clear()
                self.resetSignal.emit()

        else:
            messageBox(self, "Reset", "Jobs are running..")

    def resetButtonState(self):
        """Set clear button state"""

        if self.output.jobOutput.toPlainText() != "":
            self.btnGrid.itemAt(_Button.RESET).widget().setEnabled(True)
        else:
            self.btnGrid.itemAt(_Button.RESET).widget().setEnabled(False)

    def setDefaultAlgorithm(self):
        #
        # Algorithm
        #
        if config.data.get(config.ConfigKey.Algorithm) is not None:
            currentAlgorithm = config.data.get(config.ConfigKey.Algorithm)
            self.radioButtons[currentAlgorithm].setChecked(True)

    def setLanguage(self):
        """
        setLanguage language use in buttons/labels to be called by MainWindow
        """

        for index in range(self.frmCmdLine.rowCount()):
            widget = self.frmCmdLine.itemAt(index, QFormLayout.LabelRole).widget()
            if isinstance(widget, QPushButtonWidget):
                widget.setLanguage()
                # widget.setText("  " + _(widget.originalText) + "  ")
                # widget.setToolTip(_(widget.toolTip))

        for index in range(self.btnHBox.count()):
            widget = self.btnHBox.itemAt(index).widget()
            if isinstance(
                widget,
                (
                    QLabelWidget,
                    QPushButtonWidget,
                ),
            ):
                widget.setLanguage()

        for index in range(self.btnGrid.count()):
            widget = self.btnGrid.itemAt(index).widget()
            if isinstance(widget, QPushButtonWidget):
                widget.setLanguage()
                # widget.setText("  " + _(widget.originalText) + "  ")
                # widget.setToolTip(_(widget.toolTip))

    def toggledRadioButton(self, rButton):
        for index, rb in enumerate(self.radioButtons):
            if rb.isChecked():
                self.algorithm = index
Ejemplo n.º 16
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('Voice Player')
        self.words = []

        centralWidget = QWidget()
        self.setCentralWidget(centralWidget)
        layout = QFormLayout(centralWidget)

        self.readButton = QPushButton('Read CSV')
        self.readButton.clicked.connect(self.readCSV)
        layout.addRow('CSV File:', self.readButton)

        textLayout = QHBoxLayout()
        self.text = QLineEdit('')
        self.text.setClearButtonEnabled(True)
        textLayout.addWidget(self.text)
        self.sayButton = QPushButton('Say')
        textLayout.addWidget(self.sayButton)
        self.text.returnPressed.connect(self.sayButton.animateClick)
        self.sayButton.clicked.connect(self.say)
        layout.addRow('Text:', textLayout)

        self.voiceCombo = QComboBox()
        self.voiceCombo.currentIndexChanged.connect(self.indexChange)
        layout.addRow('Voice:', self.voiceCombo)

        self.volumeSlider = QSlider(Qt.Horizontal)
        self.volumeSlider.setMinimum(0)
        self.volumeSlider.setMaximum(100)
        self.volumeSlider.setValue(100)
        layout.addRow('Volume:', self.volumeSlider)

        self.engine = None
        engineNames = QTextToSpeech.availableEngines()
        if len(engineNames) > 0:
            engineName = engineNames[0]
            self.engine = QTextToSpeech(engineName)
            self.engine.stateChanged.connect(self.stateChanged)
            #self.setWindowTitle('QTextToSpeech Example ({})'.format(engineName))
            #self.voices = []
            #for voice in self.engine.availableVoices():
            #    self.voices.append(voice)
            #    self.voiceCombo.addItem(voice.name())
            self.voice = self.engine.availableVoices()[0]
        else:
            self.setWindowTitle('QTextToSpeech Example (no engines available)')
            self.sayButton.setEnabled(False)

    def indexChange(self, index):
        word = self.words[self.voiceCombo.currentIndex()]
        self.text.setText(word)

    def readCSV(self):
        fileDialog = QFileDialog(self)
        fileDialog.setNameFilters(['CSV File (*.csv)'])
        if fileDialog.exec_() == QDialog.Accepted:
            csvPath = fileDialog.selectedFiles()[0]
            self.words = []
            with open(csvPath) as fi:
                for line in fi:
                    line = line.strip()
                    if not line: continue
                    self.words.append(line)
            self.voiceCombo.clear()
            for word in self.words:
                self.voiceCombo.addItem(word)
            if len(self.words):
                word = self.words[self.voiceCombo.currentIndex()]
                self.text.setText(word)

    def say(self):
        self.sayButton.setEnabled(False)
        self.engine.setVoice(self.voice)
        self.engine.setVolume(float(self.volumeSlider.value()) / 100)
        text = self.text.text().strip()
        if not text:
            self.sayButton.setEnabled(True)
        else:
            self.engine.say(self.text.text())

    def stateChanged(self, state):
        if (state == QTextToSpeech.State.Ready):
            self.sayButton.setEnabled(True)
            currIdx = self.voiceCombo.currentIndex()
            count = self.voiceCombo.count()
            if currIdx + 1 < count:
                self.voiceCombo.setCurrentIndex(currIdx + 1)
                word = self.words[self.voiceCombo.currentIndex()]
                self.text.setText(word)
            else:
                self.text.setText('')
Ejemplo n.º 17
0
class AudioInfoDialog(QDialog):
    def __init__(self,
                 audios_name,
                 audios_delay,
                 audios_language,
                 audios_track_name,
                 audios_set_default,
                 audios_set_forced,
                 audios_default_value_delay,
                 audios_default_value_language,
                 audios_default_value_track_name,
                 audios_default_value_set_default,
                 audios_default_value_set_forced,
                 audio_set_default_disabled=False,
                 audio_set_forced_disabled=False,
                 disable_edit=False,
                 parent=None):
        super().__init__(parent)
        self.window_title = "Audio Info"
        self.state = "no"
        self.audios_count = len(audios_delay)

        self.messageIcon = QLabel()
        self.audio_tab_comboBox = InfoCellDialogTabComboBox(
            hint="Audios Groups")
        for i in range(self.audios_count):
            self.audio_tab_comboBox.addItem("Audio #" + str(i + 1))
        self.audio_tab_comboBox.setCurrentIndex(0)
        self.audio_tab_comboBox.currentIndexChanged.connect(
            self.update_current_audio_index)
        self.current_audio_index = 0

        self.disable_edit = disable_edit
        self.current_audio_name = audios_name
        self.current_audio_language = audios_language
        self.current_audio_delay = audios_delay
        self.current_audio_track_name = audios_track_name
        self.current_audio_set_default = audios_set_default
        self.current_audio_set_forced = audios_set_forced

        self.default_audio_language = audios_default_value_language
        self.default_audio_delay = audios_default_value_delay
        self.default_audio_track_name = audios_default_value_track_name
        self.default_audio_set_default = audios_default_value_set_default
        self.default_audio_set_forced = audios_default_value_set_forced

        self.audio_set_default_disabled = audio_set_default_disabled
        self.audio_set_forced_disabled = audio_set_forced_disabled

        self.audio_name_label = QLabel("Audio Name:")
        self.audio_name_value = QLabel(
            str(self.current_audio_name[self.current_audio_index]))
        width_to_be_fixed = 0
        for i in range(len(self.current_audio_name)):
            width_to_be_fixed = max(
                width_to_be_fixed,
                self.audio_name_value.fontMetrics().boundingRect(
                    self.current_audio_name[i]).width())
        self.audio_name_value.setFixedWidth(width_to_be_fixed + 10)
        self.audio_delay_label = QLabel("Audio Delay:")
        self.audio_delay_spin = QDoubleSpinBox()
        self.setup_audio_delay_spin()

        self.audio_language_label = QLabel("Audio Language:")
        self.audio_language_comboBox = QComboBox()
        self.setup_audio_language_comboBox()

        self.audio_track_name_label = QLabel("Audio Track Name:")
        self.audio_track_name_lineEdit = QLineEdit()
        self.setup_audio_track_name_lineEdit()

        self.audio_set_forced_label = QLabel("Audio Forced State:")
        self.audio_set_forced_checkBox = QCheckBox()
        self.setup_audio_set_forced_checkBox()

        self.audio_set_default_label = QLabel("Audio Default State:")
        self.audio_set_default_checkBox = QCheckBox()
        self.setup_audio_set_default_checkBox()

        self.yes_button = QPushButton("OK")
        self.no_button = QPushButton("Cancel")
        self.reset_button = QPushButton("Reset To Default")

        self.buttons_layout = QHBoxLayout()
        self.audio_delay_layout = QHBoxLayout()
        self.audio_language_layout = QHBoxLayout()
        self.audio_track_name_layout = QHBoxLayout()
        self.audio_set_default_layout = QHBoxLayout()
        self.audio_set_forced_layout = QHBoxLayout()
        self.buttons_layout.addWidget(QLabel(""), stretch=3)
        self.buttons_layout.addWidget(self.reset_button, stretch=2)
        self.buttons_layout.addWidget(self.yes_button, stretch=2)
        self.buttons_layout.addWidget(self.no_button, stretch=2)
        self.buttons_layout.addWidget(QLabel(""), stretch=3)
        self.audio_setting_layout = QGridLayout()
        self.audio_editable_setting_layout = QFormLayout()
        self.audio_editable_setting_layout.addRow(self.audio_name_label,
                                                  self.audio_name_value)
        self.audio_editable_setting_layout.addRow(
            self.audio_track_name_label, self.audio_track_name_lineEdit)
        self.audio_editable_setting_layout.addRow(self.audio_language_label,
                                                  self.audio_language_comboBox)
        self.audio_editable_setting_layout.addRow(self.audio_delay_label,
                                                  self.audio_delay_spin)
        self.audio_editable_setting_layout.addRow(
            self.audio_set_default_label, self.audio_set_default_checkBox)
        self.audio_editable_setting_layout.addRow(
            self.audio_set_forced_label, self.audio_set_forced_checkBox)
        self.audio_setting_layout.addWidget(self.audio_tab_comboBox, 0, 0)
        self.audio_setting_layout.addLayout(self.audio_editable_setting_layout,
                                            1, 0, 5, 2)
        self.audio_setting_layout.addWidget(self.messageIcon, 1, 3, 5, -1)

        self.main_layout = QGridLayout()
        self.main_layout.addLayout(self.audio_setting_layout, 0, 0, 2, 3)
        self.main_layout.addLayout(self.buttons_layout, 2, 0, 1, -1)
        self.main_layout.setContentsMargins(20, 20, 20, 20)
        self.setLayout(self.main_layout)

        self.setup_ui()
        self.signal_connect()

    def setup_ui(self):
        self.disable_question_mark_window()
        self.messageIcon.setPixmap(
            QtGui.QPixmap(GlobalFiles.AudioIconPath).scaledToHeight(100))
        self.set_dialog_values()
        self.set_default_buttons()
        if self.audio_set_default_disabled:
            self.audio_set_default_disable()
        if self.audio_set_forced_disabled:
            self.audio_set_forced_disable()
        if self.disable_edit:
            self.audio_track_name_lineEdit.setEnabled(False)
            self.audio_language_comboBox.setEnabled(False)
            self.audio_delay_spin.setEnabled(False)
            self.audio_set_default_checkBox.setEnabled(False)
            self.audio_set_forced_checkBox.setEnabled(False)
            self.reset_button.setEnabled(False)

        self.setup_tool_tip_hint_audio_set_default()
        self.setup_tool_tip_hint_audio_set_forced()

    def signal_connect(self):
        self.audio_track_name_lineEdit.textEdited.connect(
            self.update_current_audio_track_name)
        self.audio_delay_spin.editingFinished.connect(
            self.update_current_audio_delay)
        self.audio_language_comboBox.currentTextChanged.connect(
            self.update_current_audio_language)
        self.audio_set_default_checkBox.stateChanged.connect(
            self.update_current_audio_set_default)
        self.audio_set_forced_checkBox.stateChanged.connect(
            self.update_current_audio_set_forced)
        self.yes_button.clicked.connect(self.click_yes)
        self.no_button.clicked.connect(self.click_no)
        self.reset_button.clicked.connect(self.reset_audio_setting)

    def click_yes(self):
        self.state = "yes"
        self.close()

    def click_no(self):
        self.state = "no"
        self.close()

    def set_dialog_values(self):
        self.setWindowTitle(self.window_title)
        self.setWindowIcon(GlobalFiles.InfoSettingIcon)

    def disable_question_mark_window(self):
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, on=False)

    def increase_message_font_size(self, value):
        message_font = self.message.font()
        message_font.setPointSize(self.message.fontInfo().pointSize() + value)
        self.message.setFont(message_font)

    def set_default_buttons(self):
        self.yes_button.setDefault(True)
        self.yes_button.setFocus()

    def showEvent(self, a0: QtGui.QShowEvent) -> None:
        super().showEvent(a0)
        self.setFixedSize(self.size())

    def setup_audio_track_name_lineEdit(self):
        self.audio_track_name_lineEdit.setClearButtonEnabled(True)
        self.audio_track_name_lineEdit.setText(
            self.current_audio_track_name[self.current_audio_index])

    def setup_audio_language_comboBox(self):
        self.audio_language_comboBox.addItems(AllAudiosLanguages)
        self.audio_language_comboBox.setCurrentIndex(
            AllAudiosLanguages.index(
                self.current_audio_language[self.current_audio_index]))
        self.audio_language_comboBox.setMaxVisibleItems(8)
        self.audio_language_comboBox.setStyleSheet(
            "QComboBox { combobox-popup: 0; }")

    def setup_audio_delay_spin(self):
        # self.audio_delay_spin.setMaximumWidth(screen_size.width() // 16)
        self.audio_delay_spin.setDecimals(3)
        self.audio_delay_spin.setMinimum(-9999.0)
        self.audio_delay_spin.setMaximum(9999.0)
        self.audio_delay_spin.setSingleStep(0.5)
        self.audio_delay_spin.setValue(
            float(self.current_audio_delay[self.current_audio_index]))

    def setup_audio_set_default_checkBox(self):
        self.audio_set_default_checkBox.setText("Set Default")
        self.audio_set_default_checkBox.setChecked(
            bool(self.current_audio_set_default[self.current_audio_index]))

    def setup_audio_set_forced_checkBox(self):
        self.audio_set_forced_checkBox.setText("Set Forced")
        self.audio_set_forced_checkBox.setChecked(
            bool(self.current_audio_set_forced[self.current_audio_index]))

    def update_current_audio_track_name(self):
        self.current_audio_track_name[self.current_audio_index] = str(
            self.audio_track_name_lineEdit.text())

    def update_current_audio_delay(self):
        self.current_audio_delay[self.current_audio_index] = round(
            self.audio_delay_spin.value(), 5)

    def update_current_audio_language(self):
        self.current_audio_language[self.current_audio_index] = str(
            self.audio_language_comboBox.currentText())

    def update_current_audio_set_default(self):
        new_state = self.audio_set_default_checkBox.checkState() == Qt.Checked
        self.current_audio_set_default[self.current_audio_index] = new_state
        if new_state:
            for i in range(len(self.current_audio_set_default)):
                if i != self.current_audio_index:
                    self.current_audio_set_default[i] = False

    def update_current_audio_set_forced(self):
        new_state = self.audio_set_forced_checkBox.checkState() == Qt.Checked
        self.current_audio_set_forced[self.current_audio_index] = new_state
        if new_state:
            for i in range(len(self.current_audio_set_forced)):
                if i != self.current_audio_index:
                    self.current_audio_set_forced[i] = False

    def reset_audio_setting(self):
        self.current_audio_language[
            self.current_audio_index] = self.default_audio_language[
                self.current_audio_index]
        self.current_audio_delay[
            self.current_audio_index] = self.default_audio_delay[
                self.current_audio_index]
        self.current_audio_track_name[
            self.current_audio_index] = self.default_audio_track_name[
                self.current_audio_index]
        self.current_audio_set_default[
            self.current_audio_index] = self.default_audio_set_default[
                self.current_audio_index]
        self.current_audio_set_forced[
            self.current_audio_index] = self.default_audio_set_forced[
                self.current_audio_index]

        self.audio_language_comboBox.setCurrentIndex(
            AllAudiosLanguages.index(
                self.current_audio_language[self.current_audio_index]))
        self.audio_delay_spin.setValue(
            float(self.current_audio_delay[self.current_audio_index]))
        self.audio_track_name_lineEdit.setText(
            self.current_audio_track_name[self.current_audio_index])
        self.audio_set_default_checkBox.setChecked(
            bool(self.current_audio_set_default[self.current_audio_index]))
        self.audio_set_forced_checkBox.setChecked(
            bool(self.current_audio_set_forced[self.current_audio_index]))

    def audio_set_default_disable(self):
        self.audio_set_default_checkBox.setDisabled(True)

    def audio_set_forced_disable(self):
        self.audio_set_forced_checkBox.setDisabled(True)

    def setup_tool_tip_hint_audio_set_default(self):
        if self.audio_set_default_checkBox.isEnabled():
            self.audio_set_default_checkBox.setToolTip(
                "<nobr>set this audio to be the default audio track "
                "when play")
            self.audio_set_default_checkBox.setToolTipDuration(12000)
        else:
            self.audio_set_default_checkBox.setToolTip(
                "<nobr>set this audio to be the default audio track when play<br><b>Disabled</b> because "
                "option "
                "<b>make this audio default</b> is enabled on mux setting tab "
            )
            self.audio_set_default_checkBox.setToolTipDuration(12000)

    def setup_tool_tip_hint_audio_set_forced(self):
        if self.audio_set_forced_checkBox.isEnabled():
            self.audio_set_forced_checkBox.setToolTip(
                "<nobr>set this audio to be the forced audio track when "
                "play")
            self.audio_set_forced_checkBox.setToolTipDuration(12000)
        else:
            self.audio_set_forced_checkBox.setToolTip(
                "<nobr>set this audio to be the forced audio track when play<br><b>Disabled</b> because "
                "option "
                "<b>make this audio default and forced</b> is enabled on mux setting tab "
            )
            self.audio_set_forced_checkBox.setToolTipDuration(12000)

    def update_current_audio_index(self, new_index):
        self.current_audio_index = new_index
        self.audio_delay_spin.setValue(
            float(self.current_audio_delay[self.current_audio_index]))
        self.audio_set_default_checkBox.setChecked(
            bool(self.current_audio_set_default[self.current_audio_index]))
        self.audio_set_forced_checkBox.setChecked(
            bool(self.current_audio_set_forced[self.current_audio_index]))
        self.audio_language_comboBox.setCurrentIndex(
            AllAudiosLanguages.index(
                self.current_audio_language[self.current_audio_index]))
        self.audio_track_name_lineEdit.setText(
            self.current_audio_track_name[self.current_audio_index])
        self.audio_name_value.setText(
            str(self.current_audio_name[self.current_audio_index]))

    def execute(self):
        self.exec_()
Ejemplo n.º 18
0
class MuxSettingTab(QWidget):
    tab_clicked_signal = Signal()
    start_muxing_signal = Signal()
    update_task_bar_progress_signal = Signal(int)
    update_task_bar_paused_signal = Signal()
    update_task_bar_clear_signal = Signal()

    def __init__(self):
        super().__init__()
        self.create_widgets()
        self.setup_widgets()
        self.connect_signals()

    def connect_signals(self):
        self.tab_clicked_signal.connect(self.tab_clicked)

        self.destination_path_button.clicked.connect(self.open_select_destination_folder_dialog)

        self.only_keep_those_audios_checkBox.stateChanged.connect(
            self.only_keep_those_audios_multi_choose_comboBox.check_box_state_changed)

        self.only_keep_those_subtitles_checkBox.stateChanged.connect(
            self.only_keep_those_subtitles_multi_choose_comboBox.check_box_state_changed)

        self.make_this_audio_default_checkBox.disable_combo_box.connect(self.disable_make_this_audio_default_comboBox)

        self.make_this_subtitle_default_checkBox.disable_combo_box.connect(
            self.disable_make_this_subtitle_default_comboBox)

        self.control_queue_button.add_to_queue_clicked_signal.connect(self.add_to_queue_button_clicked)
        self.control_queue_button.start_multiplexing_clicked_signal.connect(self.start_multiplexing_button_clicked)
        self.control_queue_button.pause_multiplexing_clicked_signal.connect(self.pause_multiplexing_button_clicked)

        self.clear_job_queue_button.clicked.connect(self.clear_job_queue_button_clicked)

        self.only_keep_those_audios_multi_choose_comboBox.closeList.connect(self.only_keep_those_audios_close_list)

        self.only_keep_those_subtitles_multi_choose_comboBox.closeList.connect(
            self.only_keep_those_subtitles_close_list)

        self.make_this_audio_default_comboBox.currentTextChanged.connect(
            self.make_this_audio_default_comboBox_text_changed)

        self.make_this_subtitle_default_comboBox.currentTextChanged.connect(
            self.make_this_subtitle_default_comboBox_text_changed)

        self.abort_on_errors_checkBox.stateChanged.connect(self.abort_on_errors_state_changed)

        self.keep_log_file_checkBox.stateChanged.connect(self.keep_log_file_state_changed)
        self.job_queue_layout.update_task_bar_progress_signal.connect(self.update_task_bar_progress)
        self.job_queue_layout.paused_done_signal.connect(self.paused_done)
        self.job_queue_layout.cancel_done_signal.connect(self.cancel_done)
        self.job_queue_layout.finished_all_jobs_signal.connect(self.finished_all_jobs)
        self.job_queue_layout.pause_from_error_occurred_signal.connect(self.pause_multiplexing_button_clicked)

    def setup_widgets(self):
        self.setup_mux_setting_groupBox()
        self.setup_job_queue_groupBox()
        self.setup_destination_path_label()
        self.setup_destination_path_lineEdit()
        self.setup_destination_path_button()
        self.setup_abort_on_errors_checkBox()
        self.setup_discard_old_attachments_checkBox()
        self.setup_keep_log_file_checkBox()
        self.setup_clear_job_queue_button()
        self.setup_tool_tip_hint()
        self.setup_layouts()

    def setup_layouts(self):
        self.setup_MainLayout()
        self.mux_setting_groupBox.setLayout(self.mux_setting_layout)
        self.job_queue_groupBox.setLayout(self.job_queue_layout)
        self.setup_mux_tools_layout_first_row()
        self.setup_mux_tools_layout_second_row()
        self.setup_mux_setting_layout()
        self.setLayout(self.MainLayout)

    # noinspection PyAttributeOutsideInit
    def create_widgets(self):
        self.MainLayout = QVBoxLayout()
        self.mux_setting_groupBox = QGroupBox(self)
        self.job_queue_groupBox = QGroupBox(self)
        self.mux_setting_layout = QGridLayout()
        self.job_queue_layout = JobQueueLayout()
        self.destination_path_label = QLabel()
        self.destination_path_lineEdit = QLineEdit()
        self.destination_path_button = QPushButton()
        self.only_keep_those_audios_checkBox = OnlyKeepThoseAudiosCheckBox()
        self.only_keep_those_subtitles_checkBox = OnlyKeepThoseSubtitlesCheckBox()
        self.only_keep_those_audios_multi_choose_comboBox = AudioTracksCheckableComboBox()
        self.only_keep_those_subtitles_multi_choose_comboBox = SubtitleTracksCheckableComboBox()
        self.make_this_audio_default_checkBox = MakeThisAudioDefaultCheckBox()
        self.make_this_subtitle_default_checkBox = MakeThisSubtitleDefaultCheckBox()
        self.make_this_audio_default_comboBox = MakeThisTrackDefaultComboBox()
        self.make_this_subtitle_default_comboBox = MakeThisTrackDefaultComboBox()
        self.abort_on_errors_checkBox = QCheckBox()
        self.discard_old_attachments_checkBox = QCheckBox()
        self.keep_log_file_checkBox = QCheckBox()
        self.control_queue_button = ControlQueueButton()
        self.clear_job_queue_button = QPushButton()
        self.mux_tools_layout_first_row = QHBoxLayout()
        self.mux_tools_layout_second_row = QHBoxLayout()
        self.job_queue_tools_layout = QHBoxLayout()

    def setup_mux_setting_layout(self):
        self.mux_setting_layout.addWidget(self.destination_path_label, 0, 0)
        self.mux_setting_layout.addWidget(self.destination_path_lineEdit, 0, 1)
        self.mux_setting_layout.addWidget(self.destination_path_button, 0, 2)
        self.mux_setting_layout.addWidget(self.only_keep_those_audios_checkBox, 1, 0)
        self.mux_setting_layout.addWidget(self.only_keep_those_subtitles_checkBox, 2, 0)
        self.mux_setting_layout.addLayout(self.mux_tools_layout_first_row, 1, 1)
        self.mux_setting_layout.addLayout(self.mux_tools_layout_second_row, 2, 1)

    def setup_mux_tools_layout_first_row(self):
        self.mux_tools_layout_first_row.addWidget(self.only_keep_those_audios_multi_choose_comboBox, 2)
        self.mux_tools_layout_first_row.addWidget(self.make_this_audio_default_checkBox, 1)
        self.mux_tools_layout_first_row.addWidget(self.make_this_audio_default_comboBox, 2)
        self.mux_tools_layout_first_row.addWidget(self.abort_on_errors_checkBox, 1)
        self.mux_tools_layout_first_row.addWidget(self.keep_log_file_checkBox)

    def setup_mux_tools_layout_second_row(self):
        self.mux_tools_layout_second_row.addWidget(self.only_keep_those_subtitles_multi_choose_comboBox, 2)
        self.mux_tools_layout_second_row.addWidget(self.make_this_subtitle_default_checkBox, 1)
        self.mux_tools_layout_second_row.addWidget(self.make_this_subtitle_default_comboBox, 2)
        self.mux_tools_layout_second_row.addWidget(self.control_queue_button, 1)
        self.mux_tools_layout_second_row.addWidget(self.clear_job_queue_button, 1)

    def setup_clear_job_queue_button(self):
        self.clear_job_queue_button.setText("Clear All")
        self.clear_job_queue_button.setIcon(GlobalFiles.CleanIcon)
        self.clear_job_queue_button.setDisabled(True)

    def setup_keep_log_file_checkBox(self):
        self.keep_log_file_checkBox.setText("Keep Log File")
        self.keep_log_file_checkBox.setToolTip("log file will located in the source folder after finished muxing")

    def setup_discard_old_attachments_checkBox(self):
        self.discard_old_attachments_checkBox.setText("Discard Old Attachments ")

    def setup_abort_on_errors_checkBox(self):
        self.abort_on_errors_checkBox.setText("Abort On Errors")
        self.abort_on_errors_checkBox.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)

    def setup_destination_path_button(self):
        self.destination_path_button.setIcon(GlobalFiles.SelectFolderIcon)

    def setup_destination_path_lineEdit(self):
        self.destination_path_lineEdit.setPlaceholderText("Enter Destination Folder Path")
        self.destination_path_lineEdit.setClearButtonEnabled(True)

    def setup_destination_path_label(self):
        self.destination_path_label.setText("Videos Destination Folder :")

    def setup_MainLayout(self):
        self.MainLayout.addWidget(self.mux_setting_groupBox)
        self.MainLayout.addWidget(self.job_queue_groupBox)

    def setup_job_queue_groupBox(self):
        self.job_queue_groupBox.setTitle("Job Queue")

    def setup_mux_setting_groupBox(self):
        self.mux_setting_groupBox.setTitle("Mux Setting")

    def paintEvent(self, event: QPaintEvent):
        self.update_widgets_size()
        super().paintEvent(event)

    def resizeEvent(self, event: QResizeEvent):
        self.job_queue_layout.update_layout()
        super().resizeEvent(event)

    def update_widgets_size(self):
        self.only_keep_those_subtitles_multi_choose_comboBox.resize(
            self.only_keep_those_audios_multi_choose_comboBox.width(),
            self.only_keep_those_audios_multi_choose_comboBox.height(),
        )

        self.make_this_subtitle_default_checkBox.resize(
            self.make_this_audio_default_checkBox.width(),
            self.make_this_audio_default_checkBox.height(),
        )
        self.make_this_subtitle_default_checkBox.move(
            self.make_this_audio_default_checkBox.x(),
            self.make_this_subtitle_default_checkBox.y(),
        )

        self.make_this_subtitle_default_comboBox.resize(
            self.make_this_audio_default_comboBox.width(),
            self.make_this_audio_default_comboBox.height(),
        )
        self.make_this_subtitle_default_comboBox.move(
            self.make_this_audio_default_comboBox.x(),
            self.make_this_subtitle_default_comboBox.y(),
        )

        self.control_queue_button.move(
            self.abort_on_errors_checkBox.x(),
            self.control_queue_button.y(),
        )

        self.clear_job_queue_button.move(
            self.control_queue_button.x() + self.control_queue_button.width() + 5,
            self.clear_job_queue_button.y(),
        )

    def open_select_destination_folder_dialog(self):
        temp_folder_path = QFileDialog.getExistingDirectory(self, caption="Choose Destination Folder",
                                                            dir=GlobalSetting.LAST_DIRECTORY_PATH, )
        if temp_folder_path == "" or temp_folder_path.isspace():
            return
        elif Path(temp_folder_path) == Path(GlobalSetting.VIDEO_SOURCE_PATH):
            invalid_dialog = InvalidPathDialog(
                error_message="Source and destination videos can't be in the same folder")
            invalid_dialog.execute()
            return
        else:
            self.destination_path_lineEdit.setText(str(Path(temp_folder_path)))
            GlobalSetting.LAST_DIRECTORY_PATH = self.destination_path_lineEdit.text()
            GlobalSetting.DESTINATION_FOLDER_PATH = self.destination_path_lineEdit.text()

    def check_destination_path(self):
        temp_destination_path = self.destination_path_lineEdit.text()
        try:
            if temp_destination_path == "" or temp_destination_path.isspace():
                temp_destination_path = "[Empty Path]"
                raise Exception(
                    "[WinError 998] Empty path is Not a valid path : " + temp_destination_path)
            # check if system is windows so path must have # SOME_LETTER:\
            if os.name == 'nt':
                if temp_destination_path[1:3] != ":\\" and self.destination_path_lineEdit.text()[
                                                           1:3] != ":/":
                    raise Exception("[WinError 999] Not a valid path : " + temp_destination_path)
            makedirs(temp_destination_path, exist_ok=True)
            ## test if i can write into this path:
            test_file_name = str(time.time()) + ".txt"
            test_file_name_absolute = os.path.join(Path(temp_destination_path), Path(test_file_name))
            try:
                with open(test_file_name_absolute, 'w+') as test_file:
                    test_file.write("Test")
                os.remove(test_file_name_absolute)
            except Exception as e:
                write_to_log_file(e)
                invaild_dialog = InvalidPathDialog(window_title="Permission Denied",
                                                   error_message="MKV Muxing Batch GUI lacks write "
                                                                 "permissions on Destination folder")
                invaild_dialog.execute()
                self.destination_path_lineEdit.setText(GlobalSetting.DESTINATION_FOLDER_PATH)
                return False
        except Exception as e:
            write_to_log_file(e)
            error_message = ""
            if temp_destination_path == "[Empty Path]":
                error_message = "Enter a valid destination path"
            else:
                error_message = temp_destination_path + "\nisn't a valid path!"
            invalid_dialog = InvalidPathDialog(error_message=error_message)
            invalid_dialog.execute()
            self.destination_path_lineEdit.setText(GlobalSetting.DESTINATION_FOLDER_PATH)
            return False
        if Path(temp_destination_path) == Path(GlobalSetting.VIDEO_SOURCE_PATH):
            invalid_dialog = InvalidPathDialog(
                error_message="Source and destination videos can't be in the same folder")
            invalid_dialog.execute()
            self.destination_path_lineEdit.setText(GlobalSetting.DESTINATION_FOLDER_PATH)
            return False
        GlobalSetting.DESTINATION_FOLDER_PATH = temp_destination_path
        return True

    def setup_tool_tip_hint(self):
        self.only_keep_those_subtitles_multi_choose_comboBox.set_tool_tip_hint()
        self.only_keep_those_audios_multi_choose_comboBox.set_tool_tip_hint()
        self.make_this_subtitle_default_checkBox.set_tool_tip_hint_no_check()
        self.make_this_audio_default_checkBox.set_tool_tip_hint_no_check()

    def add_to_queue_button_clicked(self):
        self.job_queue_layout.setup_queue()
        self.enable_muxing_setting()
        if not GlobalSetting.JOB_QUEUE_EMPTY:
            self.disable_editable_widgets()
            self.control_queue_button.set_state_start_multiplexing()
            self.clear_job_queue_button.setDisabled(False)
            change_global_LogFilePath()
        else:
            self.enable_editable_widgets()
            self.setup_enable_options_for_mkv_only_options()

    def tab_clicked(self):
        self.job_queue_layout.show_necessary_table_columns()
        self.setup_enable_options_for_mkv_only_options()

    def setup_enable_options_for_mkv_only_options(self):
        if GlobalSetting.JOB_QUEUE_EMPTY:
            if GlobalSetting.VIDEO_SOURCE_MKV_ONLY:
                self.only_keep_those_audios_checkBox.setEnabled(True)
                self.only_keep_those_subtitles_checkBox.setEnabled(True)
                self.make_this_audio_default_checkBox.setEnabled(True)
                self.make_this_subtitle_default_checkBox.setEnabled(True)
                self.only_keep_those_audios_checkBox.setToolTip("")
                self.only_keep_those_subtitles_checkBox.setToolTip("")
                self.make_this_audio_default_comboBox.setToolTip("")
                self.make_this_subtitle_default_comboBox.setToolTip("")
                self.setup_tool_tip_hint()
            else:

                self.only_keep_those_subtitles_checkBox.setCheckState(Qt.Unchecked)
                self.only_keep_those_audios_checkBox.setCheckState(Qt.Unchecked)
                self.make_this_audio_default_checkBox.setCheckState(Qt.Unchecked)
                self.make_this_subtitle_default_checkBox.setCheckState(Qt.Unchecked)

                self.only_keep_those_audios_checkBox.setEnabled(False)
                self.only_keep_those_subtitles_checkBox.setEnabled(False)
                self.make_this_audio_default_checkBox.setEnabled(False)
                self.make_this_subtitle_default_checkBox.setEnabled(False)
                self.only_keep_those_audios_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files "
                                                                "are Mkv only")
                self.only_keep_those_subtitles_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files "
                                                                   "are Mkv only")

                self.make_this_audio_default_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files "
                                                                 "are Mkv only")

                self.make_this_subtitle_default_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files "
                                                                    "are Mkv only")
                self.make_this_audio_default_comboBox.setToolTip("<b>[Disabled]</b> Only works when video files "
                                                                 "are Mkv only")
                self.make_this_subtitle_default_comboBox.setToolTip("<b>[Disabled]</b> Only works when video files "
                                                                    "are Mkv only")
                self.only_keep_those_audios_multi_choose_comboBox.setToolTip(
                    "<b>[Disabled]</b> Only works when video files "
                    "are Mkv only")
                self.only_keep_those_subtitles_multi_choose_comboBox.setToolTip(
                    "<b>[Disabled]</b> Only works when video files "
                    "are Mkv only")

    def clear_job_queue_button_clicked(self):
        self.job_queue_layout.clear_queue()
        self.control_queue_button.set_state_add_to_queue()
        self.clear_job_queue_button.setDisabled(True)
        self.control_queue_button.setDisabled(False)
        self.enable_editable_widgets()
        self.enable_muxing_setting()
        self.setup_enable_options_for_mkv_only_options()
        self.update_task_bar_clear_signal.emit()

    def disable_editable_widgets(self):
        self.only_keep_those_subtitles_checkBox.setEnabled(False)
        self.only_keep_those_subtitles_multi_choose_comboBox.setEnabled(False)
        self.only_keep_those_audios_checkBox.setEnabled(False)
        self.only_keep_those_audios_multi_choose_comboBox.setEnabled(False)
        self.make_this_subtitle_default_checkBox.setEnabled(False)
        self.make_this_subtitle_default_comboBox.setEnabled(False)
        self.make_this_audio_default_checkBox.setEnabled(False)
        self.make_this_audio_default_comboBox.setEnabled(False)

    def enable_editable_widgets(self):
        self.only_keep_those_subtitles_checkBox.setEnabled(True)
        self.only_keep_those_subtitles_multi_choose_comboBox.setEnabled(
            self.only_keep_those_subtitles_checkBox.isChecked())
        self.only_keep_those_audios_checkBox.setEnabled(True)
        self.only_keep_those_audios_multi_choose_comboBox.setEnabled(self.only_keep_those_audios_checkBox.isChecked())
        self.make_this_subtitle_default_checkBox.setEnabled(True)
        self.make_this_subtitle_default_comboBox.setEnabled(self.make_this_subtitle_default_checkBox.isChecked())
        self.make_this_audio_default_checkBox.setEnabled(True)
        self.make_this_audio_default_comboBox.setEnabled(self.make_this_audio_default_checkBox.isChecked())

    def only_keep_those_audios_close_list(self):
        GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_AUDIOS_LANGUAGES = self.only_keep_those_audios_multi_choose_comboBox.languages
        GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_AUDIOS_TRACKS = self.only_keep_those_audios_multi_choose_comboBox.tracks

    def only_keep_those_subtitles_close_list(self):
        GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_SUBTITLES_LANGUAGES = self.only_keep_those_subtitles_multi_choose_comboBox.languages
        GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_SUBTITLES_TRACKS = self.only_keep_those_subtitles_multi_choose_comboBox.tracks

    def disable_make_this_subtitle_default_comboBox(self, state):
        self.make_this_subtitle_default_comboBox.setDisabled(state)
        if state:
            self.make_this_subtitle_default_comboBox.setCurrentIndex(-1)

    def disable_make_this_audio_default_comboBox(self, state):
        self.make_this_audio_default_comboBox.setDisabled(state)
        if state:
            self.make_this_audio_default_comboBox.setCurrentIndex(-1)

    def make_this_audio_default_comboBox_text_changed(self):
        GlobalSetting.MUX_SETTING_MAKE_THIS_AUDIO_DEFAULT_TRACK = str(
            self.make_this_audio_default_comboBox.currentText())

    def make_this_subtitle_default_comboBox_text_changed(self):
        GlobalSetting.MUX_SETTING_MAKE_THIS_SUBTITLE_DEFAULT_TRACK = str(
            self.make_this_subtitle_default_comboBox.currentText())

    def update_task_bar_progress(self, new_progress):
        self.update_task_bar_progress_signal.emit(new_progress)

    def enable_muxing_setting(self):
        self.destination_path_lineEdit.setEnabled(True)
        self.destination_path_button.setEnabled(True)
        self.abort_on_errors_checkBox.setEnabled(True)
        self.keep_log_file_checkBox.setEnabled(True)

    def disable_muxing_setting(self):
        self.destination_path_lineEdit.setEnabled(False)
        self.destination_path_button.setEnabled(False)
        self.abort_on_errors_checkBox.setEnabled(False)
        self.keep_log_file_checkBox.setEnabled(False)

    @staticmethod
    def abort_on_errors_state_changed(state):
        GlobalSetting.MUX_SETTING_ABORT_ON_ERRORS = bool(state)

    @staticmethod
    def keep_log_file_state_changed(state):
        GlobalSetting.MUX_SETTING_KEEP_LOG_FILE = bool(state)

    def start_multiplexing_button_clicked(self):
        at_least_one_muxing_setting_has_been_selected = check_if_at_least_one_muxing_setting_has_been_selected()
        if at_least_one_muxing_setting_has_been_selected:
            destination_path_valid = self.check_destination_path()
            if destination_path_valid:
                self.setup_log_file()
                self.control_queue_button.set_state_pause_multiplexing()
                self.disable_muxing_setting()
                self.job_queue_layout.start_muxing()
                self.start_muxing_signal.emit()
                self.clear_job_queue_button.setDisabled(True)

    def pause_multiplexing_button_clicked(self):
        self.job_queue_layout.pause_muxing()
        self.control_queue_button.setDisabled(True)
        self.control_queue_button.set_state_pausing_multiplexing()

    def paused_done(self):
        self.control_queue_button.set_state_resume_multiplexing()
        self.clear_job_queue_button.setDisabled(False)
        self.control_queue_button.setDisabled(False)
        self.update_task_bar_paused_signal.emit()

    def cancel_done(self):
        self.disable_editable_widgets()
        self.enable_muxing_setting()
        self.control_queue_button.set_state_start_multiplexing()
        self.clear_job_queue_button.setDisabled(False)
        change_global_LogFilePath()

    def finished_all_jobs(self):
        self.enable_editable_widgets()
        self.enable_muxing_setting()
        self.setup_enable_options_for_mkv_only_options()
        self.control_queue_button.set_state_start_multiplexing()
        self.control_queue_button.setDisabled(True)
        self.clear_job_queue_button.setDisabled(False)
        self.update_task_bar_clear_signal.emit()
        GlobalSetting.JOB_QUEUE_EMPTY = True
        check_if_want_to_keep_log_file()

    def setup_log_file(self):
        if self.control_queue_button.state == "START":
            open(GlobalFiles.LogFilePath, 'w+').close()
Ejemplo n.º 19
0
class App(QMainWindow):
    # ------------------------------------------
    # -- Initialize the Class
    # ------------------------------------------
    def __init__(self):
        super(App, self).__init__()

        # -- Home Directory
        self.home_path = expanduser("~")

        # -- Base Path
        # self.app_path = os.path.abspath(__file__)
        self.app_path = sys.argv[0]
        self.base_path_split = self.app_path.split('/')
        self.base_path = str('/').join(self.base_path_split[0:-1])

        # -- Files under config
        self.config_file = self.base_path + '/config/config.json'
        self.connect_file = self.base_path + '/config/connect.sh'
        self.table_file = self.base_path + '/config/table.csv'

        self.delimiter_table_row = ';'

        # -- Data of Config File (with Default Values)
        self.config_data_file = {
            'Message': {
                'FileReadSuccess': True,
                'FileReadFailed': True,
                'ColorRedefinition': True
            },
            'Window': {
                'Left': 100,
                'Top': 100,
                'Width': 640,
                'Height': 480
            },
            'Margin': {
                'Left': 11,
                'Top': 11,
                'Right': 11,
                'Bottom': 11
            },
            'Title': {
                'Label': 'SLT - Simple Login Tool - ' + __version__
            },
            'Button': {
                'Connect': {
                    'Label': 'Connect'
                },
                'Message': {
                    'Label': 'X'
                }
            },
            'Table': {
                'Header': [],
                'Column': {
                    'Color':
                    1,  # -- Number of column which used for text matching
                    'Connect': [
                        9, 1
                    ]  # -- These are those column numbers which data picked from the selected row and will be used as connection parameters
                },
                'Cell': {
                    'Color': {}
                }
            }
        }

        # -- Data of Table File
        self.table_data_file = []

        # -- Dictionary of Colors with QColor Elements
        self.color_data = {}

        # -- Central Widget
        self.central_widget = None

        # -- Main Layout
        self.main_layout = None

        # -- Input Box
        self.input_box = None

        # -- Connect Button
        self.connect_button = None

        # -- Message Button
        self.message_button = None

        # -- Message Label
        self.message_label = None
        self.message_label_count = None

        # -- Message List
        self.message_list = []

        # -- Main Table
        self.main_table = None

        # -- Status Bar
        self.status_bar = None

        # -- Messages
        self.messages = {
            'FileReadSuccess': 'INFO: File is opened for read: ',
            'FileReadFailed': 'ERROR: File could not be opened for read: ',
            'ColorRedefinition': 'WARN: Color Redefinition: '
        }

        # -- Initialize the UI
        self.initUI()

    # ------------------------------------------
    # -- Create Main Window
    # ------------------------------------------
    # def createMainWindow(self):
    #     if (self.main_window is None):
    #         self.main_window = QMainWindow(self)

    # ------------------------------------------
    # -- Create Central Widget
    # ------------------------------------------
    def createCentralWidget(self):
        if (self.central_widget is None):
            self.central_widget = QWidget()

        # -- Set Central Widget for QMainWindow
        self.setCentralWidget(self.central_widget)

    # ------------------------------------------
    # -- Create Layout
    # ------------------------------------------
    def createLayout(self):
        if (self.main_layout is None):
            self.main_layout = QGridLayout()

    # ------------------------------------------
    # -- Create Input Box
    # ------------------------------------------
    def createInputBox(self):
        if (self.input_box is None):
            self.input_box = QLineEdit()

        # -- Enable Clear Button
        self.input_box.setClearButtonEnabled(True)

        # -- Create Event if enter pressed
        # self.input_box.editingFinished.connect(self.eventSearchInTable)
        self.input_box.editingFinished.connect(self.eventConnectButtonClicked)

        # -- Create Event if text changed
        self.input_box.textChanged.connect(self.eventSearchInTable)

    # ------------------------------------------
    # -- Search Event
    # ------------------------------------------
    def eventSearchInTable(self):
        # print('Search Event. Look up text is: %s' %(self.input_box.text()))  # -- Debug
        self.refreshTable(self.input_box.text().strip())

    # ------------------------------------------
    # -- Create Connect Button
    # ------------------------------------------
    def createConnectButton(self, text):
        if (self.connect_button is None):
            self.connect_button = QPushButton(text)

        # -- Add Clicked Event
        self.connect_button.clicked.connect(self.eventConnectButtonClicked)

    # ------------------------------------------
    # -- Event for Connect Button Clicked
    # ------------------------------------------
    def eventConnectButtonClicked(self):
        connectParameters = ''
        row = 0

        # print('Connect Button Pressed')  # -- Debug

        if (self.main_table.rowCount() == 1):
            for column in self.config_data_file['Table']['Column']['Connect']:
                cellTable = self.main_table.item(row, column)
                connectParameters += ' ' + str(cellTable.text())

            self.connectExecute(connectParameters)
        # else:
        # print('More than one item in table, therefore cannot decide which one to choose')  # -- Debug

    # ------------------------------------------
    # -- Create Status Bar
    # ------------------------------------------
    def createStatusBar(self):
        if (self.status_bar is None):
            self.status_bar = QStatusBar()

        self.status_bar.addWidget(self.message_label_count, 0)
        self.status_bar.addWidget(VLine(), 0)
        self.status_bar.addWidget(self.message_label, 1)
        self.status_bar.addWidget(self.message_button, 0)

    # ------------------------------------------
    # -- Update Status Bar
    # ------------------------------------------
    def updateStatusBar(self):
        if (self.status_bar is not None):
            # -- Hide the Status Bar if the Message List is empty
            if (len(self.message_list) > 0):
                self.status_bar.show()
            else:
                self.status_bar.hide()

    # ------------------------------------------
    # -- Get Latest Message
    # ------------------------------------------
    def getLatestMessage(self):
        result = None
        length = len(self.message_list)

        if (length > 0):
            result = self.message_list[length - 1]

        return result

    # ------------------------------------------
    # -- Create Message Label
    # ------------------------------------------
    def createMessageLabel(self):
        if (self.message_label is None):
            self.message_label = QLabel(self)

        # -- Add a Text to Message Label
        # self.message_label.setText(self.getLatestMessage())
        self.updateMessageLabel()

    # ------------------------------------------
    # -- Update Message Label with Latest Entry
    # ------------------------------------------
    def updateMessageLabel(self):
        message = ''
        length = len(self.message_list)

        if (self.message_label is not None):
            if (length > 0):
                message = self.message_list[-1]

            self.message_label.setText(message)

    # ------------------------------------------
    # -- Create Message Label Count
    # ------------------------------------------
    def createMessageLabelCount(self):
        if (self.message_label_count is None):
            self.message_label_count = QLabel(self)

        self.updateMessageLabelCount()

    # ------------------------------------------
    # -- Update Message Label Count
    # ------------------------------------------
    def updateMessageLabelCount(self):
        message = ''
        length = len(self.message_list)

        if (self.message_label_count is not None):
            if (length > 0):
                message = '  ' + str(length)

            self.message_label_count.setText(message)

    # ------------------------------------------
    # -- Create Message Button
    # ------------------------------------------
    def createMessageButton(self, text):
        if (self.message_button is None):
            self.message_button = QPushButton(text)

        # -- Add Clicked Event
        self.message_button.clicked.connect(self.eventMessageButtonClicked)

    # ------------------------------------------
    # -- Event for Message Button Clicked
    # ------------------------------------------
    def eventMessageButtonClicked(self):
        length = len(self.message_list)

        # -- Remove the latest item in Message List
        if (length > 0):
            del self.message_list[length - 1]

        # -- Update Message Labels
        self.updateMessageLabel()
        self.updateMessageLabelCount()

        # -- Update the Status Bar
        self.updateStatusBar()

    # ------------------------------------------
    # -- Add a New Message to List
    # ------------------------------------------
    def addNewMessage(self, message):
        self.message_list.append(message)
        self.updateMessageLabel()

        # -- Update Status Bar
        self.updateStatusBar()

    # ------------------------------------------
    # -- Check Table Header
    # ------------------------------------------
    def checkMainTableHeader(self, hostsList):
        # -- Length of the Header defined in the config file
        lengthHeaderconfig_file = len(self.config_data_file['Table']['Header'])

        # -- Length of the First Record
        if (len(hostsList) > 0):
            lengthFirstRecord = len(hostsList[0])
        else:
            lengthFirstRecord = 0

        # -- Append the Header if the list in config file is too short
        if (lengthHeaderconfig_file < lengthFirstRecord):
            for header in range(lengthHeaderconfig_file + 1,
                                lengthFirstRecord + 1):
                self.config_data_file['Table']['Header'].append(str(header))

    # ------------------------------------------
    # -- Create Table
    # ------------------------------------------
    def createMainTable(self, hostsList):
        numCell = 0

        maxTableRow = len(hostsList)
        maxTableColumn = len(self.config_data_file['Table']['Header'])

        if (self.main_table is None):
            self.main_table = QTableWidget()

        # -- Set the Maximum Size of Table
        self.main_table.setColumnCount(maxTableColumn)
        self.main_table.setRowCount(maxTableRow)

        # -- Create the Horizontal Header of Table
        headerTableWidget = self.main_table.horizontalHeader()

        # -- Set the Table Header
        self.main_table.setHorizontalHeaderLabels(
            self.config_data_file['Table']['Header'])

        # -- Hide The Horizontal Table Header
        # self.main_table.horizontalHeader().setVisible(False)

        # -- Set the Cells to Read Only
        self.main_table.setEditTriggers(QTableWidget.NoEditTriggers)

        # -- Set Table Header Properties
        for numCell in range(0, len(self.config_data_file['Table']['Header'])):
            headerTableWidget.setSectionResizeMode(
                numCell, QHeaderView.ResizeToContents)

        # -- Set the First Column to Resizeable
        # headerTableWidget.setSectionResizeMode(0, QHeaderView.Stretch)

        # -- Set the Last Column to Resizeable
        headerTableWidget.setSectionResizeMode(maxTableColumn - 1,
                                               QHeaderView.Stretch)

        # -- Add Double Clicked Event on Table
        self.main_table.itemDoubleClicked.connect(
            self.eventMainTableDoubleClickedOnCell)

        # -- Insert Data into Table
        self.insertDataIntoTable(self.main_table, hostsList)

    # ------------------------------------------
    # -- Double Clicked on Cell Event
    # ------------------------------------------
    def eventMainTableDoubleClickedOnCell(self):
        connectParameters = ''
        row = self.main_table.currentRow()

        # print('Double Clicked on a Table Cell')  # -- Debug

        for column in self.config_data_file['Table']['Column']['Connect']:
            cellTable = self.main_table.item(row, column)
            connectParameters += ' ' + str(cellTable.text())

        self.connectExecute(connectParameters)

    # ------------------------------------------
    # -- Insert Data into the Table
    # ------------------------------------------
    def insertDataIntoTable(self, inputTable, inputRecords):
        maxHeaderColumn = len(self.config_data_file['Table']['Header'])
        maxTableColumn = len(self.config_data_file['Table']['Header'])
        maxTableRow = len(inputRecords)
        colorColumn = self.config_data_file['Table']['Column']['Color']
        numRecord = 0
        numCell = 0

        # -- Set the Maximum size of Table
        inputTable.setColumnCount(maxTableColumn)
        inputTable.setRowCount(maxTableRow)

        for record in inputRecords:
            # print('Record : %s' %(str(record)))  # -- Debug
            for cell in record:
                # print('Cell : %s' %(cell))  # -- Debug
                if (numCell < maxHeaderColumn):
                    inputTable.setItem(numRecord, numCell,
                                       QTableWidgetItem(cell))

                    # -- Set the Background Color of Cells
                    # if (record[colorColumn] in self.colorCell):
                    #     inputTable.item(numRecord, numCell).setBackground(self.colorCell[record[colorColumn]])
                    if (record[colorColumn] in self.config_data_file['Table']
                        ['Cell']['Color']):
                        nameColor = self.config_data_file['Table']['Cell'][
                            'Color'][record[colorColumn]]

                        # print('Cell: %s, %s, %s' %(record[colorColumn], nameColor, self.color_data[nameColor]))  # -- Debug

                        inputTable.item(numRecord, numCell).setBackground(
                            self.color_data[nameColor])

                numCell += 1
            numCell = 0
            numRecord += 1

        inputTable.move(0, 0)

    # ------------------------------------------
    # -- Refresh Table
    # ------------------------------------------
    def refreshTable(self, searchText):
        found = False
        filteredHostsList = []

        # print('Refresh table data.')  # -- Debug

        # -- Clean the Table
        for row in range(self.main_table.rowCount() - 1, -1, -1):
            # print('Remove row: %s' %(str(row))) # -- Debug
            self.main_table.removeRow(row)

        self.main_table.show()

        # -- Update the table_data_file with searchText
        for record in self.table_data_file:
            found = False
            for cell in record:
                if (searchText == ''
                        or cell.lower().find(searchText.lower()) != -1):
                    # print('Found: %s' %(str(cell)))  # -- Debug
                    found = True

            if (found):
                filteredHostsList.append(record)

        # -- Recreate Table Data with filtered Values
        self.insertDataIntoTable(self.main_table, filteredHostsList)

        # -- Refresh the QTableWidget (required due to screen artifact)
        self.main_table.hide()
        self.main_table.show()

    # ------------------------------------------
    # -- Read Config File
    # ------------------------------------------
    def readConfigFile(self, filename):
        fileHandle = None
        message = ''

        try:
            fileHandle = open(filename, 'r')
        except IOError:
            message = self.messages['FileReadFailed'] + filename
            print(message)

            # -- Message
            if (self.config_data_file['Message']['FileReadFailed'] is True):
                self.addNewMessage(message)
        else:
            message = self.messages['FileReadSuccess'] + filename
            print(message)

            # -- Update the Default Data Values with the New Ones
            # self.config_data_file = json.load(fileHandle)
            self.config_data_file.update(json.load(fileHandle))

            # -- Add Colors to the List
            for key, value in self.config_data_file['Color'].items():
                # -- Check the Length of Value (must have 3 elements [R,G,B])
                if (len(value) == 3):
                    self.addColor(key, value[0], value[1], value[2])

            # -- Message
            if (self.config_data_file['Message']['FileReadSuccess'] is True):
                self.addNewMessage(message)

            # print('JSON: %s' %(self.config_data_file))  # -- Debug
        finally:
            if (fileHandle):
                fileHandle.close()

    # ------------------------------------------
    # -- Add Color to the Dictionary
    # ------------------------------------------
    def addColor(self, name, red, green, blue):
        # print('Add Color: %s [%d,%d,%d]' %(name, red, green, blue))  # -- Debug

        # -- Check Red
        if (type(red) is int):
            if (red < 0 or red > 255):
                red = 255
        else:
            red = 255

        # -- Check Green
        if (type(green) is int):
            if (green < 0 or green > 255):
                green = 255
        else:
            green = 255

        # -- Check Blue
        if (type(blue) is int):
            if (blue < 0 or blue > 255):
                blue = 255
        else:
            blue = 255

        # print('Add Color: %s [%d,%d,%d]' %(name, red, green, blue))  # -- Debug

        # -- Add the Color to the Dictionary
        if (name not in self.color_data):
            self.color_data[name] = QColor(red, green, blue)
        else:
            # -- Message
            if (self.config_data_file['Message']['ColorRedefinition'] is True):
                self.addNewMessage(self.messages['ColorRedefinition'] + name)

    # ------------------------------------------
    # -- Read CSV File
    # ------------------------------------------
    def readCsvFile(self, filename):
        fileHandle = None
        result = []
        message = ''

        try:
            fileHandle = open(filename, 'r')
        except IOError:
            message = self.messages['FileReadFailed'] + filename
            print(message)

            # -- Message
            if (self.config_data_file['Message']['FileReadFailed'] is True):
                self.addNewMessage(message)
        else:
            message = self.messages['FileReadSuccess'] + filename
            print(message)

            # -- Message
            if (self.config_data_file['Message']['FileReadSuccess'] is True):
                self.addNewMessage(message)

            fileContent = fileHandle.readlines()

            for line in fileContent:
                strippedLine = line.strip()

                if (strippedLine != ''):
                    if (strippedLine[0] != '#'):
                        # result.append(list(strippedLine.split(self.delimiter_table_row)))  # -- List Items are not Stripped
                        result.append(
                            list(item.strip() for item in strippedLine.split(
                                self.delimiter_table_row))
                        )  # -- List Items are Stripped
                        # print(strippedLine)  # -- Debug

            # -- Debug
            # for line in result:
            #    for column in line:
            #        print('[\'%s\']' %(str(column)), end='')
            #    print('')
        finally:
            if (fileHandle):
                fileHandle.close()

        return result

    # ------------------------------------------
    # -- Execute the Connect Command in Shell
    # ------------------------------------------
    def connectExecute(self, parameters):
        # print('Run: %s %s' %(self.connect_file, parameters))  # -- Debug

        os.system(self.connect_file + ' ' + parameters)

    # ------------------------------------------
    # -- UI Initialization
    # ------------------------------------------
    def initUI(self):
        # -- Read the Config File
        self.readConfigFile(self.config_file)

        # -- Read the Table CSV File
        self.table_data_file = self.readCsvFile(self.table_file)

        # -- Create GUI Elements
        self.createCentralWidget()
        self.createLayout()

        self.createInputBox()
        self.createConnectButton(
            self.config_data_file['Button']['Connect']['Label'])
        self.checkMainTableHeader(self.table_data_file)
        self.createMainTable(self.table_data_file)

        self.createMessageLabel()
        self.createMessageLabelCount()
        self.createMessageButton(
            self.config_data_file['Button']['Message']['Label'])

        self.createStatusBar()
        self.updateStatusBar()

        # -- Set Window Title
        self.setWindowTitle(self.config_data_file['Title']['Label'])

        # -- Set Window Geometry
        self.setGeometry(self.config_data_file['Window']['Left'],
                         self.config_data_file['Window']['Top'],
                         self.config_data_file['Window']['Width'],
                         self.config_data_file['Window']['Height'])

        # -- Set Layout Margins
        self.main_layout.setContentsMargins(
            self.config_data_file['Margin']['Left'],
            self.config_data_file['Margin']['Top'],
            self.config_data_file['Margin']['Right'],
            self.config_data_file['Margin']['Bottom'])

        # -- Set Layout
        self.central_widget.setLayout(self.main_layout)

        # -- Add Widgets to Layout
        self.main_layout.addWidget(self.input_box, 0, 0, 1, 1)
        self.main_layout.addWidget(self.connect_button, 0, 1, 1, 1)
        self.main_layout.addWidget(self.main_table, 1, 0, 1, 2)

        # -- Set Status Bar for QMainWindow
        self.setStatusBar(self.status_bar)
Ejemplo n.º 20
0
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()

        self.proxyModel = QSortFilterProxyModel()
        self.proxyModel.setDynamicSortFilter(True)

        self.sourceGroupBox = QGroupBox("Original Model")
        self.proxyGroupBox = QGroupBox("Sorted/Filtered Model")

        self.sourceView = QTreeView()
        self.sourceView.setRootIsDecorated(False)
        self.sourceView.setAlternatingRowColors(True)

        self.proxyView = QTreeView()
        self.proxyView.setRootIsDecorated(False)
        self.proxyView.setAlternatingRowColors(True)
        self.proxyView.setModel(self.proxyModel)
        self.proxyView.setSortingEnabled(True)

        self.sortCaseSensitivityCheckBox = QCheckBox("Case sensitive sorting")
        self.filterCaseSensitivityCheckBox = QCheckBox("Case sensitive filter")

        self.filterPatternLineEdit = QLineEdit()
        self.filterPatternLineEdit.setClearButtonEnabled(True)
        self.filterPatternLabel = QLabel("&Filter pattern:")
        self.filterPatternLabel.setBuddy(self.filterPatternLineEdit)

        self.filterSyntaxComboBox = QComboBox()
        self.filterSyntaxComboBox.addItem("Regular expression",
                                          REGULAR_EXPRESSION)
        self.filterSyntaxComboBox.addItem("Wildcard",
                                          WILDCARD)
        self.filterSyntaxComboBox.addItem("Fixed string",
                                          FIXED_STRING)
        self.filterSyntaxLabel = QLabel("Filter &syntax:")
        self.filterSyntaxLabel.setBuddy(self.filterSyntaxComboBox)

        self.filterColumnComboBox = QComboBox()
        self.filterColumnComboBox.addItem("Subject")
        self.filterColumnComboBox.addItem("Sender")
        self.filterColumnComboBox.addItem("Date")
        self.filterColumnLabel = QLabel("Filter &column:")
        self.filterColumnLabel.setBuddy(self.filterColumnComboBox)

        self.filterPatternLineEdit.textChanged.connect(self.filterRegExpChanged)
        self.filterSyntaxComboBox.currentIndexChanged.connect(self.filterRegExpChanged)
        self.filterColumnComboBox.currentIndexChanged.connect(self.filterColumnChanged)
        self.filterCaseSensitivityCheckBox.toggled.connect(self.filterRegExpChanged)
        self.sortCaseSensitivityCheckBox.toggled.connect(self.sortChanged)

        sourceLayout = QHBoxLayout()
        sourceLayout.addWidget(self.sourceView)
        self.sourceGroupBox.setLayout(sourceLayout)

        proxyLayout = QGridLayout()
        proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3)
        proxyLayout.addWidget(self.filterPatternLabel, 1, 0)
        proxyLayout.addWidget(self.filterPatternLineEdit, 1, 1, 1, 2)
        proxyLayout.addWidget(self.filterSyntaxLabel, 2, 0)
        proxyLayout.addWidget(self.filterSyntaxComboBox, 2, 1, 1, 2)
        proxyLayout.addWidget(self.filterColumnLabel, 3, 0)
        proxyLayout.addWidget(self.filterColumnComboBox, 3, 1, 1, 2)
        proxyLayout.addWidget(self.filterCaseSensitivityCheckBox, 4, 0, 1, 2)
        proxyLayout.addWidget(self.sortCaseSensitivityCheckBox, 4, 2)
        self.proxyGroupBox.setLayout(proxyLayout)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.sourceGroupBox)
        mainLayout.addWidget(self.proxyGroupBox)
        self.setLayout(mainLayout)

        self.setWindowTitle("Basic Sort/Filter Model")
        self.resize(500, 450)

        self.proxyView.sortByColumn(1, Qt.AscendingOrder)
        self.filterColumnComboBox.setCurrentIndex(1)

        self.filterPatternLineEdit.setText("Andy|Grace")
        self.filterCaseSensitivityCheckBox.setChecked(True)
        self.sortCaseSensitivityCheckBox.setChecked(True)

    def setSourceModel(self, model):
        self.proxyModel.setSourceModel(model)
        self.sourceView.setModel(model)

    def filterRegExpChanged(self):
        syntax_nr = self.filterSyntaxComboBox.currentData()
        pattern = self.filterPatternLineEdit.text()
        if syntax_nr == WILDCARD:
            pattern = QRegularExpression.wildcardToRegularExpression(pattern)
        elif syntax_nr == FIXED_STRING:
            pattern = QRegularExpression.escape(pattern)

        regExp = QRegularExpression(pattern)
        if not self.filterCaseSensitivityCheckBox.isChecked():
            options = regExp.patternOptions()
            options |= QRegularExpression.CaseInsensitiveOption
            regExp.setPatternOptions(options)
        self.proxyModel.setFilterRegularExpression(regExp)

    def filterColumnChanged(self):
        self.proxyModel.setFilterKeyColumn(self.filterColumnComboBox.currentIndex())

    def sortChanged(self):
        if self.sortCaseSensitivityCheckBox.isChecked():
            caseSensitivity = Qt.CaseSensitive
        else:
            caseSensitivity = Qt.CaseInsensitive

        self.proxyModel.setSortCaseSensitivity(caseSensitivity)
Ejemplo n.º 21
0
class MainWindow(QMainWindow):
    """Main class for interacting with the applications GUI."""
    @Slot(str)
    def startProgress(self, message):
        """Shows that the window is busy doing some work."""
        self.translateButton.setEnabled(False)
        self.dictsCombo.setEnabled(False)
        label = QLabel(message)
        label.setAlignment(Qt.AlignHCenter)
        progressBar = QProgressBar()
        progressBar.setRange(0, 0)
        self.statusBar().clearMessage()
        self.statusBar().addWidget(label, 1)
        self.statusBar().addWidget(progressBar, 1)
        QGuiApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

    @Slot()
    def endProgress(self):
        """Shows that the window is ready for the interaction."""
        self.statusBar().setParent(None)
        self.statusBar().showMessage(self.tr("Done"), 2000)
        QGuiApplication.restoreOverrideCursor()
        self.translateButton.setEnabled(True)
        self.dictsCombo.setEnabled(True)

    @Slot()
    def about(self):
        """Shows the "about" message box."""
        title = self.tr("About FreeLingvo")
        text = self.tr(
            "<b>FreeLingvo</b> is a dictionary search application"
            " that can work with over 140 dictionaries without"
            " Internet connection and is available under the"
            " GNU General Public License v3.<br><br>"
            "To search for translations in the selected"
            " dictionary, you must enter the desired word"
            " in the field and press \"Enter\" or click the"
            " \"translate\" button. You can also enter a sentence."
            " In this case, the sentence will be divided into"
            " separate words and possible combinations of these words."
            " The program will search for each word and combination"
            " in the selected dictionary, in which case the"
            " output can be large.<br><br>"
            "<b>Homepage:</b>"
            "<a href=\"https://github.com/ache2014/FreeLingvo\">"
            " GitHub</a><br>"
            "<b>Contact:</b>"
            "<a href=\"mailto:[email protected]\">"
            " [email protected]</a>")
        QMessageBox.about(self, title, text)

    @Slot(list)
    def showTranslations(self, translations):
        """Shows translations in the translations browser"""
        if translations:
            text = "<hr>".join(translations)
        else:
            text = self.tr("Sorry, no translations were found for:")
            text += "<br><b>{}</b>".format(self.searchText.text())
        cursor = self.translationsBrowser.textCursor()
        cursor.select(QTextCursor.Document)
        cursor.insertHtml(text)

    @Slot(str)
    def changeFontSize(self, size):
        """Changes the font size for the translations browser."""
        self.translationsBrowser.setFont(QFont(self.font().family(),
                                               int(size)))
        self.update()

    def __init__(self, parent=None, *args, appctxt=None, **kwargs):
        """Initializes all GUI elements and a separate thread."""
        super().__init__(parent)
        self.appctxt = appctxt
        self.worker = Worker(self)
        self.workerThread = QThread()
        self.worker.moveToThread(self.workerThread)
        self.workerThread.finished.connect(self.worker.deleteLater)
        self.worker.started.connect(self.startProgress)
        self.worker.ended.connect(self.endProgress)
        self.worker.translationsReady.connect(self.showTranslations)
        self.workerThread.start()

        screenGeometry = QGuiApplication.screens()[0].geometry()
        self.setGeometry(screenGeometry.width() / 5,
                         screenGeometry.height() / 5,
                         screenGeometry.width() / 3,
                         screenGeometry.height() / 3)
        self.setMinimumSize(screenGeometry.width() / 4,
                            screenGeometry.height() / 4)

        self.fileMenu = self.menuBar().addMenu(self.tr("&File"))
        self.exitAct = self.fileMenu.addAction(self.tr("&Exit"))
        self.exitAct.setStatusTip(self.tr("Exit from FreeLingvo"))
        self.exitAct.triggered.connect(self.close)

        self.helpMenu = self.menuBar().addMenu(self.tr("&Help"))
        self.aboutAct = self.helpMenu.addAction(self.tr("&About"))
        self.aboutAct.setStatusTip(
            self.tr("Show information about FreeLingvo"))
        self.aboutAct.triggered.connect(self.about)

        self.searchText = QLineEdit()
        self.searchText.setPlaceholderText(
            self.tr("What word(s) to look for?"))
        self.searchText.setClearButtonEnabled(True)
        self.searchText.returnPressed.connect(self.worker.findTranslations)

        self.translateButton = QPushButton(self.tr("Translate"))
        self.translateButton.clicked.connect(self.worker.findTranslations)

        self.dictsCombo = QComboBox()
        self.dictsCombo.setInsertPolicy(QComboBox.InsertAlphabetically)
        self.dictsCombo.setToolTip(
            self.tr("Dictionary used to search for words"))
        dictNames = os.listdir(self.appctxt.get_resource("dictionaries"))
        dictNames = [name.replace(".tei", "") for name in dictNames]
        self.dictsCombo.addItems(dictNames)
        self.dictsCombo.currentIndexChanged[str].connect(self.worker.loadDict)
        self.dictsCombo.setCurrentIndex(1)

        self.translationsBrowser = QTextBrowser()
        self.translationsBrowser.setUndoRedoEnabled(True)

        self.undoButton = QPushButton(
            QIcon(self.appctxt.get_resource("images/arrow_back.png")), "")
        self.undoButton.setEnabled(False)
        self.undoButton.setToolTip(self.tr("Show previous translation"))
        self.undoButton.clicked.connect(self.translationsBrowser.undo)
        self.translationsBrowser.undoAvailable.connect(
            self.undoButton.setEnabled)

        self.redoButton = QPushButton(
            QIcon(self.appctxt.get_resource("images/arrow_forward.png")), "")
        self.redoButton.setEnabled(False)
        self.redoButton.setToolTip(self.tr("Show next translation"))
        self.redoButton.clicked.connect(self.translationsBrowser.redo)
        self.translationsBrowser.redoAvailable.connect(
            self.redoButton.setEnabled)

        self.sizeLabel = QLabel(self.tr("Font size:"))
        self.sizeCombo = QComboBox()
        for size in QFontDatabase.standardSizes():
            self.sizeCombo.addItem(str(size))
        self.sizeCombo.setCurrentText(str(self.font().pointSize()))
        self.sizeCombo.currentIndexChanged[str].connect(self.changeFontSize)

        self.controlsLayout = QHBoxLayout()
        self.controlsLayout.addWidget(self.searchText)
        self.controlsLayout.addWidget(self.translateButton)
        self.controlsLayout.addWidget(self.dictsCombo)

        self.browserToolsLayout = QHBoxLayout()
        self.browserToolsLayout.addWidget(self.undoButton)
        self.browserToolsLayout.addWidget(self.redoButton)
        self.browserToolsLayout.addStretch(1)
        self.browserToolsLayout.addWidget(self.sizeLabel)
        self.browserToolsLayout.addWidget(self.sizeCombo)

        self.centralLayout = QVBoxLayout()
        self.centralLayout.addLayout(self.controlsLayout)
        self.centralLayout.addLayout(self.browserToolsLayout)
        self.centralLayout.addWidget(self.translationsBrowser)

        centralWidget = QWidget()
        centralWidget.setLayout(self.centralLayout)
        self.setCentralWidget(centralWidget)

        self.statusBar().showMessage(self.tr("Ready"), 2000)

    def closeEvent(self, event):
        """Destroys the thread properly before exiting."""
        self.workerThread.quit()
        self.workerThread.wait()
        super().closeEvent(event)
Ejemplo n.º 22
0
class SubtitleInfoDialog(QDialog):
    def __init__(self,
                 subtitle_name="Test",
                 subtitle_delay=0.0,
                 subtitle_language=Default_Subtitle_Language,
                 subtitle_track_name="Test",
                 subtitle_set_default=False,
                 subtitle_set_forced=False,
                 subtitle_default_value_delay=0.0,
                 subtitle_default_value_language=Default_Subtitle_Language,
                 subtitle_default_value_track_name="Test",
                 subtitle_default_value_set_default=False,
                 subtitle_default_value_set_forced=False,
                 subtitle_set_default_disabled=False,
                 subtitle_set_forced_disabled=False,
                 disable_edit=False,
                 parent=None):
        super().__init__(parent)
        self.window_title = "Subtitle Info"
        self.state = "no"
        self.messageIcon = QLabel()

        self.disable_edit = disable_edit

        self.current_subtitle_language = str(subtitle_language)
        self.current_subtitle_delay = str(subtitle_delay)
        self.current_subtitle_track_name = str(subtitle_track_name)
        self.current_subtitle_set_default = subtitle_set_default
        self.current_subtitle_set_forced = subtitle_set_forced

        self.default_subtitle_language = str(subtitle_default_value_language)
        self.default_subtitle_delay = str(subtitle_default_value_delay)
        self.default_subtitle_track_name = str(
            subtitle_default_value_track_name)
        self.default_subtitle_set_default = subtitle_default_value_set_default
        self.default_subtitle_set_forced = subtitle_default_value_set_forced

        self.subtitle_set_default_disabled = subtitle_set_default_disabled
        self.subtitle_set_forced_disabled = subtitle_set_forced_disabled

        self.subtitle_name_label = QLabel("Subtitle Name:")
        self.subtitle_name_value = QLabel(str(subtitle_name))

        self.subtitle_delay_label = QLabel("Subtitle Delay:")
        self.subtitle_delay_spin = QDoubleSpinBox()
        self.setup_subtitle_delay_spin()

        self.subtitle_language_label = QLabel("Subtitle Language:")
        self.subtitle_language_comboBox = QComboBox()
        self.setup_subtitle_language_comboBox()

        self.subtitle_track_name_label = QLabel("Subtitle Track Name:")
        self.subtitle_track_name_lineEdit = QLineEdit()
        self.setup_subtitle_track_name_lineEdit()

        self.subtitle_set_forced_label = QLabel("Subtitle Forced State:")
        self.subtitle_set_forced_checkBox = QCheckBox()
        self.setup_subtitle_set_forced_checkBox()

        self.subtitle_set_default_label = QLabel("Subtitle Default State:")
        self.subtitle_set_default_checkBox = QCheckBox()
        self.setup_subtitle_set_default_checkBox()

        self.yes_button = QPushButton("OK")
        self.no_button = QPushButton("Cancel")
        self.reset_button = QPushButton("Reset To Default")

        self.buttons_layout = QHBoxLayout()
        self.subtitle_delay_layout = QHBoxLayout()
        self.subtitle_language_layout = QHBoxLayout()
        self.subtitle_track_name_layout = QHBoxLayout()
        self.subtitle_set_default_layout = QHBoxLayout()
        self.subtitle_set_forced_layout = QHBoxLayout()
        self.buttons_layout.addWidget(QLabel(""), stretch=3)
        self.buttons_layout.addWidget(self.reset_button, stretch=2)
        self.buttons_layout.addWidget(self.yes_button, stretch=2)
        self.buttons_layout.addWidget(self.no_button, stretch=2)
        self.buttons_layout.addWidget(QLabel(""), stretch=3)
        self.subtitle_setting_layout = QGridLayout()
        self.subtitle_changeble_setting_layout = QFormLayout()
        self.subtitle_changeble_setting_layout.addRow(self.subtitle_name_label,
                                                      self.subtitle_name_value)
        self.subtitle_changeble_setting_layout.addRow(
            self.subtitle_track_name_label, self.subtitle_track_name_lineEdit)
        self.subtitle_changeble_setting_layout.addRow(
            self.subtitle_language_label, self.subtitle_language_comboBox)
        self.subtitle_changeble_setting_layout.addRow(
            self.subtitle_delay_label, self.subtitle_delay_spin)
        self.subtitle_changeble_setting_layout.addRow(
            self.subtitle_set_default_label,
            self.subtitle_set_default_checkBox)
        self.subtitle_changeble_setting_layout.addRow(
            self.subtitle_set_forced_label, self.subtitle_set_forced_checkBox)

        self.subtitle_setting_layout.addLayout(
            self.subtitle_changeble_setting_layout, 0, 0, 5, 2)
        self.subtitle_setting_layout.addWidget(self.messageIcon, 0, 3, 5, -1)

        self.main_layout = QGridLayout()
        self.main_layout.addLayout(self.subtitle_setting_layout, 0, 0, 2, 3)
        self.main_layout.addLayout(self.buttons_layout, 2, 0, 1, -1)
        self.main_layout.setContentsMargins(20, 20, 20, 20)
        self.setLayout(self.main_layout)

        self.setup_ui()
        self.signal_connect()

    def setup_ui(self):
        self.disable_question_mark_window()
        self.messageIcon.setPixmap(
            QtGui.QPixmap(GlobalFiles.SubtitleIconPath).scaledToHeight(100))
        self.set_dialog_values()
        self.set_default_buttons()
        if self.subtitle_set_default_disabled:
            self.subtitle_set_default_disable()
        if self.subtitle_set_forced_disabled:
            self.subtitle_set_forced_disable()
        if self.disable_edit:
            self.subtitle_track_name_lineEdit.setEnabled(False)
            self.subtitle_language_comboBox.setEnabled(False)
            self.subtitle_delay_spin.setEnabled(False)
            self.subtitle_set_default_checkBox.setEnabled(False)
            self.subtitle_set_forced_checkBox.setEnabled(False)
            self.reset_button.setEnabled(False)

        self.setup_tool_tip_hint_subtitle_set_default()
        self.setup_tool_tip_hint_subtitle_set_forced()

    def signal_connect(self):
        self.subtitle_track_name_lineEdit.textEdited.connect(
            self.update_current_subtitle_track_name)
        self.subtitle_delay_spin.editingFinished.connect(
            self.update_current_subtitle_delay)
        self.subtitle_language_comboBox.currentTextChanged.connect(
            self.update_current_subtitle_language)
        self.subtitle_set_default_checkBox.stateChanged.connect(
            self.update_current_subtitle_set_default)
        self.subtitle_set_forced_checkBox.stateChanged.connect(
            self.update_current_subtitle_set_forced)
        self.yes_button.clicked.connect(self.click_yes)
        self.no_button.clicked.connect(self.click_no)
        self.reset_button.clicked.connect(self.reset_subtitle_setting)

    def click_yes(self):
        self.state = "yes"
        self.close()

    def click_no(self):
        self.close()

    def set_dialog_values(self):
        self.setWindowTitle(self.window_title)
        self.setWindowIcon(GlobalFiles.InfoSettingIcon)

    def disable_question_mark_window(self):
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, on=False)

    def increase_message_font_size(self, value):
        message_font = self.message.font()
        message_font.setPointSize(self.message.fontInfo().pointSize() + value)
        self.message.setFont(message_font)

    def set_default_buttons(self):
        self.yes_button.setDefault(True)
        self.yes_button.setFocus()

    def showEvent(self, a0: QtGui.QShowEvent) -> None:
        super().showEvent(a0)
        self.setFixedSize(self.size())

    def setup_subtitle_track_name_lineEdit(self):
        self.subtitle_track_name_lineEdit.setClearButtonEnabled(True)
        self.subtitle_track_name_lineEdit.setText(
            self.current_subtitle_track_name)

    def setup_subtitle_language_comboBox(self):
        self.subtitle_language_comboBox.addItems(AllSubtitlesLanguages)
        self.subtitle_language_comboBox.setCurrentIndex(
            AllSubtitlesLanguages.index(self.current_subtitle_language))
        self.subtitle_language_comboBox.setMaxVisibleItems(8)
        self.subtitle_language_comboBox.setStyleSheet(
            "QComboBox { combobox-popup: 0; }")

    def setup_subtitle_delay_spin(self):
        # self.subtitle_delay_spin.setMaximumWidth(screen_size.width() // 16)
        self.subtitle_delay_spin.setDecimals(3)
        self.subtitle_delay_spin.setMinimum(-9999.0)
        self.subtitle_delay_spin.setMaximum(9999.0)
        self.subtitle_delay_spin.setSingleStep(0.5)
        self.subtitle_delay_spin.setValue(float(self.current_subtitle_delay))

    def setup_subtitle_set_default_checkBox(self):
        self.subtitle_set_default_checkBox.setText("Set Default")
        self.subtitle_set_default_checkBox.setChecked(
            bool(self.current_subtitle_set_default))

    def setup_subtitle_set_forced_checkBox(self):
        self.subtitle_set_forced_checkBox.setText("Set Forced")
        self.subtitle_set_forced_checkBox.setChecked(
            bool(self.current_subtitle_set_forced))

    def update_current_subtitle_track_name(self):
        self.current_subtitle_track_name = str(
            self.subtitle_track_name_lineEdit.text())

    def update_current_subtitle_delay(self):
        self.current_subtitle_delay = round(self.subtitle_delay_spin.value(),
                                            5)

    def update_current_subtitle_language(self):
        self.current_subtitle_language = str(
            self.subtitle_language_comboBox.currentText())

    def update_current_subtitle_set_default(self):
        self.current_subtitle_set_default = (
            self.subtitle_set_default_checkBox.checkState() == Qt.Checked)

    def update_current_subtitle_set_forced(self):
        self.current_subtitle_set_forced = (
            self.subtitle_set_forced_checkBox.checkState() == Qt.Checked)

    def reset_subtitle_setting(self):
        self.current_subtitle_language = self.default_subtitle_language
        self.current_subtitle_delay = self.default_subtitle_delay
        self.current_subtitle_track_name = self.default_subtitle_track_name
        self.current_subtitle_set_default = self.default_subtitle_set_default
        self.current_subtitle_set_forced = self.default_subtitle_set_forced

        self.subtitle_language_comboBox.setCurrentIndex(
            AllSubtitlesLanguages.index(self.current_subtitle_language))
        self.subtitle_delay_spin.setValue(float(self.current_subtitle_delay))
        self.subtitle_track_name_lineEdit.setText(
            self.current_subtitle_track_name)
        self.subtitle_set_default_checkBox.setChecked(
            bool(self.current_subtitle_set_default))
        self.subtitle_set_forced_checkBox.setChecked(
            bool(self.current_subtitle_set_forced))

    def subtitle_set_default_disable(self):
        self.subtitle_set_default_checkBox.setDisabled(True)

    def subtitle_set_forced_disable(self):
        self.subtitle_set_forced_checkBox.setDisabled(True)

    def setup_tool_tip_hint_subtitle_set_default(self):
        if self.subtitle_set_default_checkBox.isEnabled():
            self.subtitle_set_default_checkBox.setToolTip(
                "<nobr>set this subtitle to be the default subtitle track "
                "when play")
            self.subtitle_set_default_checkBox.setToolTipDuration(12000)
        else:
            self.subtitle_set_default_checkBox.setToolTip(
                "<nobr>set this subtitle to be the default subtitle track when play<br><b>Disabled</b> because "
                "option "
                "<b>make this subtitle default</b> is enabled on mux setting tab "
            )
            self.subtitle_set_default_checkBox.setToolTipDuration(12000)

    def setup_tool_tip_hint_subtitle_set_forced(self):
        if self.subtitle_set_forced_checkBox.isEnabled():
            self.subtitle_set_forced_checkBox.setToolTip(
                "<nobr>set this subtitle to be the forced subtitle track when "
                "play")
            self.subtitle_set_forced_checkBox.setToolTipDuration(12000)
        else:
            self.subtitle_set_forced_checkBox.setToolTip(
                "<nobr>set this subtitle to be the forced subtitle track when play<br><b>Disabled</b> because "
                "option "
                "<b>make this subtitle default and forced</b> is enabled on mux setting tab "
            )
            self.subtitle_set_forced_checkBox.setToolTipDuration(12000)

    def execute(self):
        self.exec_()
Ejemplo n.º 23
0
class MainWindow(QMainWindow):

    # noinspection PyUnresolvedReferences
    def __init__(self, dbpath):
        super(MainWindow, self).__init__()

        # 'Add to collection' window
        self.addWindow = None

        # 'Import games' window
        self.importWindow = None

        # Side panel
        self.sidePanel = SidePanel()

        # Tables and their databases
        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName(dbpath)
        if not db.open():
            logger.critical(f"Couldn't open database: {db.lastError().text()}")
            QMessageBox.critical(None, "Database Error", db.lastError().text())
        self.gamesTableView = Table("games", db)
        self.gamesTableView.doubleClick.connect(self.sidePanel.showDetails)
        self.consolesTableView = Table("consoles", db)
        self.consolesTableView.doubleClick.connect(self.sidePanel.showDetails)
        self.accessoriesTableView = Table("accessories", db)
        self.accessoriesTableView.doubleClick.connect(self.sidePanel.showDetails)
        self.tableViewList = [self.gamesTableView,
                              self.consolesTableView,
                              self.accessoriesTableView]

        self.allPlatforms = set()
        self.allRegions = set()
        self.allGenres = set()
        self.allYears = set()
        for table in self.tableViewList:
            for row in table.ownedItems():
                self.allPlatforms.add(row["platform"])
                self.allRegions.add(row["region"])
                self.allYears.add(row["year"])
                # Split multi-genre entries
                for genre in row["genre"].split(", "):
                    self.allGenres.add(genre)

        self.filterDock = FilterDock(sorted(self.allPlatforms, key=str.lower),
                                     sorted(self.allRegions, key=str.lower),
                                     sorted(self.allGenres, key=str.lower),
                                     sorted(self.allYears, key=str.lower))

        # Overview tab
        self.overview = Overview(self.tableViewList)

        # Randomizer tab
        self.randomizer = Randomizer(self.gamesTableView.ownedItems(),
                                     sorted(self.allPlatforms, key=str.lower),
                                     sorted(self.allGenres, key=str.lower))
        self.randomizer.consoleList.itemClicked.connect(self.updateStatusbar)
        self.randomizer.genreList.itemClicked.connect(self.updateStatusbar)
        self.randomizer.genreMatchExclusiveCB.stateChanged.connect(self.updateStatusbar)
        self.randomizer.btnAll.clicked.connect(self.updateStatusbar)
        self.randomizer.btnNone.clicked.connect(self.updateStatusbar)

        ## MainWindow layout
        # Widgets
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.tab = QTabWidget()

        self.toolbar = self.addToolBar("Exit")
        self.toolbar.addAction(self.buttonActions("exit"))
        self.toolbar.addAction(self.buttonActions("add"))
        self.toolbar.addAction(self.buttonActions("import"))

        self.fileMenu = self.menuBar().addMenu(self.tr("&File"))
        self.fileMenu.addAction(self.buttonActions("add"))
        self.fileMenu.addAction(self.buttonActions("export"))
        self.fileMenu.addAction(self.buttonActions("import"))
        self.fileMenu.addAction(self.buttonActions("steam"))
        self.fileMenu.addAction(self.buttonActions("fetch"))
        self.fileMenu.insertSeparator(self.buttonActions("exit"))
        self.fileMenu.addAction(self.buttonActions("exit"))
        self.viewMenu = self.menuBar().addMenu(self.tr("&View"))
        self.viewMenu.addAction(self.buttonActions("owned"))
        self.viewMenu.addAction(self.buttonActions("delnotowned"))
        self.viewMenu.addAction(self.buttonActions("value"))
        self.helpMenu = self.menuBar().addMenu(self.tr("&Help"))
        self.helpMenu.addAction(self.buttonActions("about"))

        self.statusProgressBar = QProgressBar()
        self.statusProgressBar.setMaximumSize(100, 15)
        self.statusProgressBar.setRange(0, 0)
        self.statusProgressBar.setVisible(False)
        self.statusBar().addPermanentWidget(self.statusProgressBar)

        # Search stuff
        self.searchLabel = QLabel("Search")
        self.searchLabel.setVisible(False)
        self.searchBox = QLineEdit()
        self.searchBox.setVisible(False)
        self.searchBox.setClearButtonEnabled(True)
        # self.searchBox.textChanged.connect(self.search)
        self.searchBox.returnPressed.connect(self.search)
        self.searchBtn = QPushButton("Search")
        self.searchBtn.clicked.connect(self.search)
        self.searchBtn.setVisible(False)
        self.filterBtn = QPushButton("Filter")
        self.filterBtn.clicked.connect(self.filterDock.toggleVisibility)
        self.filterBtn.setVisible(False)

        # Tab layout.
        self.tab.addTab(self.overview.widget, "Overview")
        self.tab.addTab(self.gamesTableView, "Games")
        self.tab.addTab(self.consolesTableView, "Consoles")
        self.tab.addTab(self.accessoriesTableView, "Accessories")
        self.tab.addTab(self.randomizer.widget, "Randomizer")
        self.tab.currentChanged.connect(self.search)
        self.tab.currentChanged.connect(self.sidePanel.hideDetails)
        # Connect sidePanel's saved signal to corresponding table's updateData()
        # TODO: Update the sets of platforms and genres properly
        self.sidePanel.saved.connect(self.tableViewList[self.tab.currentIndex()].updateData)
        self.sidePanel.saved.connect(lambda: self.randomizer.updateLists(self.gamesTableView.ownedItems(),
                                                                         sorted(self.allPlatforms, key=str.lower),
                                                                         sorted(self.allGenres, key=str.lower)))

        # Main layout
        self.tabHbox = QHBoxLayout()
        self.tabHbox.addWidget(self.tab, 1)
        self.tabHbox.addWidget(self.sidePanel, 1)
        self.advSearchHbox = QHBoxLayout()
        self.advSearchHbox.addWidget(self.filterDock, 0)
        self.searchHbox = QHBoxLayout()
        self.searchHbox.addWidget(self.searchLabel, 0)
        self.searchHbox.addWidget(self.searchBox, 1)
        self.searchHbox.addWidget(self.filterBtn, 0)
        self.searchHbox.addWidget(self.searchBtn, 0)
        self.mainLayout = QVBoxLayout()
        self.mainLayout.addLayout(self.tabHbox, 1)
        self.mainLayout.addLayout(self.advSearchHbox, 0)
        self.mainLayout.addLayout(self.searchHbox, 0)
        self.centralWidget.setLayout(self.mainLayout)

        # Make sure screen geometry is big enough. Otherwise set window to maximized.
        gSize = QApplication.desktop().availableGeometry()
        if gSize.width() <= 1280 or gSize.height() <= 768:
            logger.info("Screen geometry smaller than 1280x768. Setting window to maximized mode.")
            self.showMaximized()
        else:
            self.resize(1280, 768)
            self.center()

        self.setWindowTitle(f"Game Collection Manager v{_VERSION}")
        self.statusBar().showMessage("")

    def about(self):
        aboutMsg = QMessageBox()
        aboutMsg.setIcon(QMessageBox.Information)
        aboutMsg.setWindowTitle("About")
        aboutMsg.setText("<h2>Game Collection Manager</h2>")
        aboutMsg.setInformativeText(f"Version {_VERSION}\n")
        aboutMsg.exec_()
        self.search()

    def addToCollection(self):
        """
        Adds data to the collection using InputWindow
        """

        # Loop until user enters valid data
        while True:
            self.addWindow = InputWindow(self.allPlatforms)
            if self.addWindow.exec_() == QDialog.Accepted:
                data = self.addWindow.returnData()

                if data['platform'].isspace() or data['name'] == "":
                    msgBox = QMessageBox()
                    msgBox.setIcon(QMessageBox.Information)
                    msgBox.setWindowTitle("Invalid entry")
                    msgBox.setText("Platform and name cannot be empty")
                    msgBox.exec_()
                    continue

                # Update Platform, Region, Genre, and Year in filter dock if necessary
                if data["platform"] not in self.allPlatforms:
                    self.allPlatforms.add(data["platform"])
                    self.filterDock.updatePlatforms(sorted(self.allPlatforms, key=str.lower))
                if data["region"] not in self.allRegions:
                    self.allRegions.add(data["region"])
                    self.filterDock.updateRegions(sorted(self.allRegions, key=str.lower))
                if data["genre"] not in self.allGenres:
                    self.allGenres.add(data["genre"])
                    self.filterDock.updateGenres(sorted(self.allGenres, key=str.lower))
                if data["year"] not in self.allYears:
                    self.allYears.add(data["year"])
                    self.filterDock.updateYears(sorted(self.allYears, key=str.lower))

                if "game" in data.keys():
                    self.gamesTableView.addData(data)
                    self.overview.updateData(self.gamesTableView)
                    self.randomizer.updateLists(self.gamesTableView.ownedItems(),
                                                sorted(self.allPlatforms, key=str.lower),
                                                sorted(self.allGenres, key=str.lower))
                elif "console" in data.keys():
                    self.consolesTableView.addData(data)
                    self.overview.updateData(self.consolesTableView)
                elif "accessory" in data.keys():
                    self.accessoriesTableView.addData(data)
                    self.overview.updateData(self.accessoriesTableView)
                self.search()
            else:
                break

    def deleteFromCollection(self):
        currentTab = self.tab.currentIndex()

        if 0 < currentTab < 4:
            msgBox = QMessageBox()
            msgBox.setWindowTitle("Delete items")
            msgBox.setText("Are you sure?")
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
            msgBox.setDefaultButton(QMessageBox.Cancel)
            ok = msgBox.exec_()

            if ok == QMessageBox.Ok:
                rows = []
                indexes = self.tableViewList[currentTab-1].selectedIndexes()
                for index in indexes:
                    rows.append(index.row())
                self.tableViewList[currentTab-1].deleteData(rows)
                self.overview.updateData(self.tableViewList[currentTab-1])
                if currentTab == 1:
                    self.randomizer.updateLists(self.gamesTableView.ownedItems(),
                                                sorted(self.allPlatforms, key=str.lower),
                                                sorted(self.allGenres, key=str.lower))
                self.search()

    def deleteNotOwned(self):
        """
        Deletes items in table that are not owned. Not owned items are items that
        don't have either the item itself, the box, or the manual.
        """
        currentTab = self.tab.currentIndex()

        if 0 < currentTab < 4:
            msgBox = QMessageBox()
            msgBox.setWindowTitle("Remove not owned items")
            msgBox.setText("Are you sure?")
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
            msgBox.setDefaultButton(QMessageBox.Cancel)
            ok = msgBox.exec_()

            if ok == QMessageBox.Ok:
                self.tableViewList[currentTab-1].deleteNotOwned()
                self.search()

    def fetchInfo(self):
        """
        Fetches info for all games from MobyGames. Sleeps for 5 seconds
        between game so we don't annoy their servers.
        :return:
        """
        msgBox = QMessageBox()
        msgBox.setWindowTitle("Fetch info for all games")
        msgBox.setText("This will take a long time. Are you sure?")
        msgBox.setIcon(QMessageBox.Warning)
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Cancel)
        ok = msgBox.exec_()

        if ok == QMessageBox.Ok:
            games = self.gamesTableView.ownedItems()
            for game in games:
                info = getMobyRelease(game["name"], game["platform"], game["region"])
                price = getPriceData(game["name"], game["platform"], game["region"])
                paidPrice = game["price"].split(",")[0]
                info["price"] = ",".join((paidPrice, price["loose"], price["cib"], price["new"]))
                info["id"] = game["id"]
                self.gamesTableView.updateData(info)

                if "image" in info.keys() and info["image"] != "":
                    coverDir = path.join("data", "images", "covers")
                    id = str(game["id"]) + ".jpg"
                    imageData = requests.get(info["image"]).content

                    if not path.exists(path.join(coverDir, id)):
                        with open(path.join(coverDir, id), "wb") as f:
                            f.write(imageData)

                sleep(5)  # Be nice

    def importToDatabase(self):
        """
        Imports all games from selected platforms into database as not owned.
        This is to make it easier for the user to quickly go through the games
        in a platform and check which games they own.
        """
        self.importWindow = ImportWindow()
        if self.importWindow.exec_() == QDialog.Accepted:
            data, platforms, regions = self.importWindow.returnData()
            self.statusProgressBar.setVisible(True)
            self.gamesTableView.addData(data)
            self.statusProgressBar.setVisible(False)

            for platform in platforms:
                if platform not in self.allPlatforms:
                    self.allPlatforms.add(platform)
                    self.filterDock.updatePlatforms(sorted(self.allPlatforms, key=str.lower))
            for region in regions:
                if region not in self.allRegions:
                    self.allRegions.add(region)
                    self.filterDock.updateRegions(sorted(self.allRegions, key=str.lower))
            self.search()

    def importSteamLibrary(self):
        apiKey, ok = QInputDialog.getText(self, "Import Steam Library", "Enter Steam API Key:")
        if ok and not (apiKey.isspace() or apiKey == ""):
            steamID, ok = QInputDialog.getText(self, "Import Steam Library", "Enter Steam User ID:")
            if ok and not (steamID.isspace() or steamID == ""):
                try:
                    games = getSteamLibrary(apiKey, steamID)
                except (PermissionError, ValueError) as e:
                    msgBox = QMessageBox(QMessageBox.Critical, "Error", "An error occured.")
                    msgBox.setInformativeText(str(e))
                    msgBox.exec_()
                else:
                    if "Steam" not in self.allPlatforms:
                        self.allPlatforms.add("Steam")
                        self.allRegions.add("Steam")
                        self.filterDock.updatePlatforms(sorted(self.allPlatforms, key=str.lower))
                        self.filterDock.updateRegions(sorted(self.allRegions, key=str.lower))
                        self.gamesTableView.addData(games)
                    else:  # Only add games not already in collection
                        existingGames = []
                        query = QSqlQuery()
                        query.exec_("SELECT Name from games WHERE Region='Steam'")
                        while query.next():
                            existingGames.append(query.value(0))

                        for game in games:
                            if game["name"] not in existingGames:
                                self.gamesTableView.addData(game)
                    self.overview.updateData(self.gamesTableView)
                    self.randomizer.updateLists(self.gamesTableView.ownedItems(),
                                                sorted(self.allPlatforms, key=str.lower),
                                                sorted(self.allGenres, key=str.lower))
                    self.search()

    def exportToCSV(self):
        def doexport():
            filetype = filetypes.currentText()
            exportTables = []
            db = self.consolesTableView.model.database()
            if tablesBox.currentIndex() == 0:
                for table in tables[1:]:
                    exportTables.append(table.lower())
            elif tablesBox.currentIndex() == 1:
                exportTables.append("games")
            elif tablesBox.currentIndex() == 2:
                exportTables.append("consoles")
            elif tablesBox.currentIndex() == 3:
                exportTables.append("accessories")

            sql2csv(db, exportTables, filetype)
            exportWindow.close()

        exportWindow = QDialog()

        tables = ["All", "Games", "Consoles", "Accessories"]
        tablesLabel = QLabel("Tables to export")
        tablesBox = QComboBox()
        # tablesBox.addItem(None, text="All")
        tablesBox.addItems(tables)
        tablesLayout = QHBoxLayout()
        tablesLayout.addWidget(tablesLabel)
        tablesLayout.addWidget(tablesBox)

        filetypesLabel = QLabel("Filetype")
        filetypes = QComboBox()
        filetypes.addItems(["csv", "tsv"])
        filetypesLayout = QHBoxLayout()
        filetypesLayout.addWidget(filetypesLabel)
        filetypesLayout.addWidget(filetypes)

        # filenameLabel = QLabel("Filename")
        # filename = QLineEdit()
        # filesLayout = QHBoxLayout()
        # filesLayout.addWidget(filenameLabel)
        # filesLayout.addWidget(filename)

        ok = QPushButton("Ok")
        ok.clicked.connect(doexport)
        cancel = QPushButton("Cancel")
        cancel.clicked.connect(exportWindow.close)
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(ok)
        buttonLayout.addWidget(cancel)

        layout = QVBoxLayout()
        layout.addLayout(tablesLayout)
        # layout.addLayout(filesLayout)
        layout.addLayout(filetypesLayout)
        layout.addLayout(buttonLayout)

        exportWindow.setLayout(layout)
        exportWindow.exec_()

    # noinspection PyCallByClass,PyTypeChecker
    def buttonActions(self, action: str) -> QAction:
        addAct = QAction(QIcon().fromTheme("list-add"), "&Add to collection...", self)
        addAct.setShortcut("Ctrl+A")
        addAct.setToolTip("Add to collection")
        addAct.triggered.connect(self.addToCollection)

        delText = "&Delete row"
        currentTab = self.tab.currentIndex()
        if 0 < currentTab < 4:
            if len(self.tableViewList[currentTab-1].selectedIndexes()) > 1:
                delText += "s"
        delAct = QAction(QIcon().fromTheme("edit-delete"), delText, self)
        delAct.setToolTip("Delete from collection")
        delAct.triggered.connect(self.deleteFromCollection)

        detAct = QAction(QIcon.fromTheme("text-x-generic-template"), "Details...", self)
        detAct.setToolTip("Open details side-panel")
        detAct.triggered.connect(self.tableViewList[currentTab-1].rowData)

        expAct = QAction(QIcon.fromTheme("text-x-generic-template"), "&Export as csv...", self)
        expAct.setShortcut("Ctrl+E")
        expAct.setToolTip("Export table as CSV file")
        expAct.triggered.connect(self.exportToCSV)

        impAct = QAction(QIcon.fromTheme("insert-object"), "&Import platform template...", self)
        impAct.setShortcut("Ctrl+I")
        impAct.setToolTip("Import games to database")
        impAct.triggered.connect(self.importToDatabase)

        stmAct = QAction(QIcon.fromTheme("insert-object"), "Import Steam Library...", self)
        stmAct.triggered.connect(self.importSteamLibrary)

        ownAct = QAction("Hide games not in collection", self)
        ownAct.setCheckable(True)
        ownAct.setChecked(True)
        ownAct.triggered.connect(self.toggleOwnedFilter)

        delNotOwned = QAction(QIcon().fromTheme("edit-delete"), "Remove items not in collection", self)
        delNotOwned.setToolTip("Remove items that are not owned from database")
        delNotOwned.triggered.connect(self.deleteNotOwned)

        aboutAct = QAction(QIcon.fromTheme("help-about"), "Abou&t", self)
        aboutAct.setToolTip("About Game Collection Manager")
        aboutAct.triggered.connect(self.about)

        exitAct = QAction(QIcon.fromTheme("application-exit"), "&Exit", self)
        exitAct.setShortcut("Ctrl+Q")
        exitAct.setToolTip("Exit application")
        exitAct.triggered.connect(self.close)

        infoAct = QAction("Debug: Print row info", self)
        infoAct.triggered.connect(self.info)

        fetchAct = QAction("Fetch info for all games...", self)
        fetchAct.setToolTip("Tries to fetch info for all games from MobyGames")
        fetchAct.triggered.connect(self.fetchInfo)

        valAct = QAction("Total value of collection", self)
        valAct.setToolTip("Rough estimate of the total value of collection")
        valAct.triggered.connect(self.totalValue)

        act = {"add": addAct, "del": delAct, "det": detAct, "export": expAct,
               "import": impAct, "steam": stmAct, "owned": ownAct,
               "delnotowned": delNotOwned, "about": aboutAct, "exit": exitAct,
               "info": infoAct, "fetch": fetchAct, "value": valAct}

        return act.get(action)

    def center(self):
        """Centers window on screen"""

        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def contextMenuEvent(self, event):
        """Re-implements context menu functionality for our needs."""
        cmenu = QMenu(self)

        currentTab = self.tab.currentIndex()

        if 0 < currentTab < 4:
            cmenu.addAction(self.buttonActions("det"))
            cmenu.addAction(self.buttonActions("del"))
            cmenu.addAction(self.buttonActions("info"))
            cmenu.exec_(self.mapToGlobal(event.pos()))

        self.search()

    def info(self):
        currentTab = self.tab.currentIndex()
        indexes = self.tableViewList[currentTab-1].selectedIndexes()
        rows = [index.row() for index in indexes]
        for _ in rows:
            self.tableViewList[currentTab-1].rowInfo()

    def search(self):
        """Filters table contents based on user input"""

        currentTab = self.tab.currentIndex()

        if 0 < currentTab < 4:
            searchText = self.searchBox.text()
            self.searchLabel.setVisible(True)
            self.searchBox.setVisible(True)
            self.filterBtn.setVisible(True)
            self.searchBtn.setVisible(True)
            self.filterDock.setItemType(currentTab)
            itemCount = self.tableViewList[currentTab - 1].filterTable(searchText, self.filterDock.getSelections())

            if searchText != "" or len(self.filterDock.getSelections()) > 0:
                self.statusBar().showMessage("Found {} {}.".format(itemCount,
                                                                   self.tableViewList[currentTab-1].model.tableName()))
            else:
                self.updateStatusbar()
        else:
            self.searchLabel.setVisible(False)
            self.searchBox.setVisible(False)
            self.filterBtn.setVisible(False)
            self.searchBtn.setVisible(False)
            if self.filterDock.isVisible():
                self.filterDock.toggleVisibility()

    def toggleOwnedFilter(self):
        for table in self.tableViewList:
            table.setHideNotOwned(False) if table.hideNotOwned\
                else table.setHideNotOwned(True)
        currentTab = self.tab.currentIndex()
        if 0 < currentTab < 4:
            self.tableViewList[currentTab-1].filterTable(self.searchBox.text(), self.filterDock.getSelections())
        self.search()

    def totalValue(self):
        value = 0.0
        items = []
        for table in self.tableViewList:
            items.extend(table.ownedItems())

        for item in items:
            if item["item"] == "Yes" and item["box"] == "Yes" and item["manual"] == "Yes":
                price = item["price"].split(",")[2]
            else:
                price = item["price"].split(",")[1]

            if price == "N/A":
                value += 0
                continue
            value += float(price.lstrip("$"))

        displayMsgBox("Collection value", "Rough estimate of collection's value.",
                      f"<h2>${str(value)}</h2>", "information")

    def updateStatusbar(self):
        currentTab = self.tab.currentIndex()
        itemType = ["games", "consoles", "accessories"]

        if currentTab == 0:
            self.statusBar().showMessage("")
        elif 0 < currentTab < 4:
            numItems = self.tableViewList[currentTab-1].ownedCount
            if self.tableViewList[currentTab-1].hideNotOwned:
                self.statusBar().showMessage(f"{numItems} {itemType[currentTab-1]} in collection.")
            else:
                self.statusBar().showMessage("Showing {} {} ({} {} in collection).".format(
                    self.tableViewList[currentTab-1].allCount,
                    itemType[currentTab-1],
                    numItems,
                    itemType[currentTab-1]))
        elif currentTab == 4:
            platforms = self.randomizer.consoleList.selectedItems()
            genres = self.randomizer.genreList.selectedItems()
            self.statusBar().showMessage("Select platforms or genre to randomize from.")
            if len(platforms) > 0 or len(genres) > 0:
                self.statusBar().showMessage(f"Selecting from {self.randomizer.gameCount()} games.")
            return