Exemplo n.º 1
0
    def showFolder(self, path):
        "displays current path, truncating as needed"
        if not path: return

        ell, sl = '\u2026', os.path.sep  # ellipsis, slash chars
        lfg, rfg = Qt.ElideLeft, Qt.ElideRight
        lst, wdh = os.path.basename(path), self.folderLabel.width()

        path = path.replace(os.path.altsep or '\\', sl)
        self.folderLabel.setToolTip(path)

        # truncate folder location
        fnt = QFontMetrics(self.folderLabel.font())
        txt = str(fnt.elidedText(path, lfg, wdh))

        if len(txt) <= 1:  # label is way too short
            self.folderLabel.setText('\u22ee' if txt != sl else txt)
            return  # but when would this happen?

        # truncate some more (don't show part of a folder name)
        if len(txt) < len(path) and txt[1] != sl:
            txt = ell + sl + txt.split(sl, 1)[-1]

            # don't truncate remaining folder name from the left
            if txt[2:] != lst and len(txt[2:]) < len(lst) + 2:
                txt = str(fnt.elidedText(ell + sl + lst, rfg, wdh))
        # you'd think len(txt) < len(lst) would work, but no; you'd be wrong

        self.folderLabel.setText(txt)
Exemplo n.º 2
0
    def elidePath(self):
        "displays current path, truncating as needed"
        lfg, rfg = Qt.ElideLeft, Qt.ElideRight
        label = self.folderLabel
        wdh = label.width()
        el, sl = u'\u2026', os.sep  # ellipsis, slash chrs
        base, sub = self.base, self.sub

        if self._pht and not sub:  # using placeholder text as sub folder
            sub = str(self.subfolderInput.placeholderText())
        use_sub = self.subfolderCB.isChecked()
        if not base: return

        # assemble path, determine bottom (last) folder
        if not sub or not use_sub: path, lst = base, os.path.basename(base)
        else: path, lst = os.path.join(base, sub), sub
        path = path.replace(os.altsep or '\\', sl)

        # truncate folder location
        fnt = QFontMetrics(self.folderLabel.font())
        txt = str(fnt.elidedText(path, lfg, wdh))

        if len(txt) <= 1:  # label is way too short
            label.setToolTip(path)  #; label.setText(u'\u22ee')
            label.setText(u'\u22ee' if txt != sl else txt)
            return  # nothing more can be done about this, so...

        # truncate some more (don't show part of a folder name)
        if len(txt) < len(path) and txt[1] != sl:
            txt = el + sl + txt.split(sl, 1)[-1]

            # don't truncate remaining folder name from the left
            if txt[2:] != lst and len(txt) - 4 < len(lst):
                txt = str(fnt.elidedText(el + sl + lst, rfg, wdh))
                if sub: sub = txt.split(sl, 1)[-1]

        if use_sub and sub:  # highlight sub folder (if there's one)
            col = u'<span style="color:#ff5500;">{}</span>'  #cd4400
            txt = col.format(sub).join(txt.rsplit(sub, 1))
            path = col.format(lst).join(path.rsplit(lst, 1))

        self.subfolderInput.setToolTip(sub)
        label.setText(txt)
        label.setToolTip(path)
    def updateText(self):
        count_tracks = 0
        count_languages = 0
        tracks = []
        languages = []
        tracks_text = []
        languages_text = []
        text = ""
        for i in range(self.model().rowCount()):
            if self.model().item(i).checkState() == Qt.Checked:
                if self.model().item(i).text().find("Track") != -1:
                    count_tracks += 1
                    tracks.append(self.model().item(i).text())
                    tracks_text.append(
                        self.model().item(i).text().split(" ")[1])

                elif self.model().item(i).text() in AllSubtitlesLanguages:
                    count_languages += 1
                    languages.append(self.model().item(i).text())
                    languages_text.append(self.model().item(i).text())
        self.tracks = tracks_text
        self.languages = languages_text
        if count_tracks > 0:
            tracks_text = "Tracks: [" + ", ".join(tracks_text) + "]"
            text = tracks_text
        if count_languages > 0:
            languages_text = "Languages: [" + ", ".join(languages_text) + "]"
            if text != "":
                text = text + "," + languages_text
            else:
                text = languages_text

        # Compute elided text (with "...")
        metrics = QFontMetrics(self.lineEdit().font())
        elided_text = metrics.elidedText(text, Qt.ElideRight,
                                         self.lineEdit().width())
        if elided_text != "":
            non_italic_font = self.lineEdit().font()
            non_italic_font.setItalic(False)
            self.lineEdit().setFont(non_italic_font)
            self.lineEdit().setText(elided_text)
            if count_tracks > 0:
                self.hint = tracks_text
                if count_languages > 0:
                    self.hint = self.hint + "<br>" + languages_text
            elif count_languages > 0:
                self.hint = languages_text
        else:
            italic_font = self.lineEdit().font()
            italic_font.setItalic(True)
            self.lineEdit().setFont(italic_font)
            self.lineEdit().setText(self.empty_selection_string)
            self.hint = self.empty_selection_hint_string
        self.setToolTip(self.hint)
Exemplo n.º 4
0
    def updateText(self):
        texts = []
        for i in range(self.model().rowCount()):
            if self.model().item(i).checkState() == Qt.Checked:
                texts.append(self.model().item(i).text())
        text = ", ".join(texts)

        # Compute elided text (with "...")
        metrics = QFontMetrics(self.lineEdit().font())
        elidedText = metrics.elidedText(text, Qt.ElideRight, self.lineEdit().width())
        self.lineEdit().setText(elidedText)
Exemplo n.º 5
0
 def resize_column(self, column_index):
     if column_index == self.column_ids["Name"]:
         for i in range(self.rowCount()):
             metrics = QFontMetrics(
                 self.cellWidget(i, self.column_ids["Name"]).font())
             elided_text = metrics.elidedText(
                 self.data[i].video_name_with_spaces, Qt.ElideRight,
                 self.columnWidth(self.column_ids["Name"]))
             self.data[i].video_name_displayed = chr(0x200E) + elided_text
             self.cellWidget(i, self.column_ids["Name"]).setText(
                 self.data[i].video_name_displayed)
     self.update()
Exemplo n.º 6
0
    def elidePath(self):
        "displays current path, truncating as needed"
        Lflg, Rflg = Qt.ElideLeft, Qt.ElideRight

        labl = self.pathLabel
        vl, el, sl = u'\u22ee', u'\u2026', os.sep
        path, wdth = self.path, labl.width()
        base = os.path.basename(path)

        # truncate folder location
        font = QFontMetrics(labl.font())
        text = str(font.elidedText(path, Lflg, wdth))
        if len(text) <= 1:
            labl.setText(vl if text != sl else text)
            return

        # truncate some more (don't show part of a folder name)
        if len(text) < len(path) and text[1] != sl:
            text = el + sl + text.split(sl, 1)[-1]

            # don't truncate remaining folder name from the left
            if text[2:] != base and len(text) - 4 < len(base):
                text = str(font.elidedText(el + sl + base, Rflg, wdth))
        labl.setText(text)
    def updateText(self):
        extensions_text = []
        for i in range(self.model().rowCount()):
            if self.model().item(i).checkState() == Qt.Checked:
                extensions_text.append(self.model().item(i).text())

        text = ', '.join(extensions_text)

        # Compute elided text (with "...")
        metrics = QFontMetrics(self.lineEdit().font())
        elided_text = metrics.elidedText(text, Qt.ElideRight,
                                         self.lineEdit().width())
        if elided_text != "":
            non_italic_font = self.lineEdit().font()
            non_italic_font.setItalic(False)
            self.lineEdit().setFont(non_italic_font)
            self.lineEdit().setText(elided_text)
            self.hint = "<nobr>Extensions: [" + text + "]"
        self.setToolTip(self.hint)
Exemplo n.º 8
0
    def paintEvent(self, _: QPaintEvent) -> None:
        """Qt Paint Event: ensures the title-bar text is elided properly and stays centered"""
        painter = QPainter()
        painter.begin(self)
        painter.setPen(self.__font_pen)

        # bold font for macOS window titles
        font = self.font()
        if sys.platform in ["darwin", "linux"]:
            font.setBold(True)
        font_metrics = QFontMetrics(font)

        # calculate text properties
        text_width: int = self.width(
        ) - self.__button_bar_width - self.__margin
        text: str = font_metrics.elidedText(self.__original_text,
                                            Qt.ElideRight, text_width)

        # calculate height
        br: QRect = font_metrics.boundingRect(text)
        if br.height() > 0:
            self.__br_height = br.height()
        py = self.__ofs_y - self.__br_height / 2.0
        br_width = br.width()

        # calculate width
        px = (self.width() - br_width - WIDTH_PADDING_PX) / 2.0
        if px < self.__button_bar_width:
            if self.__window_buttons_position == WINDOW_BUTTONS_RIGHT:
                if text != self.__original_text:
                    px = self.__margin
                else:
                    px = px - (self.__button_bar_width - px)
            else:
                px = self.__button_bar_width

        # draw title
        rect = QRectF(px, py, br_width + WIDTH_PADDING_PX, self.__br_height)
        painter.setFont(font)
        if DEBUG:
            painter.setBrush(QBrush(QColor('#ff0000')))
            painter.drawRect(rect)
        painter.drawText(rect, Qt.AlignLeft, text)
Exemplo n.º 9
0
class MainWindow(QMainWindow):
    def __init__(self, model, logic):
        QMainWindow.__init__(self)

        self.logger = logging.getLogger(__name__)

        self.model = model
        self.logic = logic

        self.ui = Ui_MainWindow_Extend()
        self.ui.setupUi(self)

        self.close_window = CloseWindow()
        self.preview_window = PreviewWindow()

        self.ui.receiver_file_label.setVisible(False)
        self.ui.status.setText('You haven\'t sent anything!')

        self.fm = QFontMetrics(
            self.ui.to_email_label.font())  # for setting text ellipsis
        # self.ui.msg_entry.installEventFilter(self)

        compulsory_list = []
        compulsory_list.append(self.ui.email_column_combo)
        compulsory_list.append(self.ui.receiver_file_label)
        compulsory_list.append(self.ui.my_password_entry)
        compulsory_list.append(self.ui.my_email_entry)

        optional_list = []
        optional_list.append(self.ui.subject_entry)
        optional_list.append(self.ui.msg_entry)
        optional_list.append(self.ui.personalised_att_combo)

        # listen for ui event signals
        self.ui.msg_entry.cursorPositionChanged.connect(self.adjust_slider)
        self.ui.send_mail_btn.clicked.connect(self.switch_to_email_pg)
        self.ui.status_btn.clicked.connect(self.switch_to_status_pg)

        # connect ui to logic
        self.ui.my_email_entry.setFocus()
        self.hide_error_message()

        self.ui.browse_file_btn.clicked.connect(self.browse_file)
        self.ui.attach_btn.clicked.connect(self.attach_file)
        self.ui.send_btn.clicked.connect(
            lambda: self.send_email(compulsory_list, optional_list, True))
        self.ui.preview_btn.clicked.connect(
            lambda: self.open_preview_window(compulsory_list, optional_list))

        # listen for logic event signals
        getattr(self.logic, 'signal_' +
                str(4)).connect(lambda: self.show_no_subject_pop_up(
                    compulsory_list, optional_list))
        getattr(self.logic,
                'signal_' + str(0)).connect(self.show_email_column_error)
        getattr(self.logic,
                'signal_' + str(1)).connect(self.show_receiver_email_error)
        getattr(self.logic,
                'signal_' + str(2)).connect(self.show_password_error)
        getattr(self.logic,
                'signal_' + str(3)).connect(self.show_my_email_error)
        self.logic.attachment_limit_reached.connect(
            self.ui.invalid_byte_size_error.show)
        self.logic.sending_start.connect(self.show_sending_start)
        self.logic.success_email.connect(self.update_successful_status)
        self.logic.fail_email.connect(self.update_fail_status)
        self.logic.sending_done.connect(self.show_sending_finish)
        self.logic.send_progress.connect(self.update_progress_bar)
        self.logic.estimate_time_finish.connect(
            self.update_estimated_time_finish)

    def update_estimated_time_finish(self, duration):
        num_hour = int(duration / 3600)
        num_minute = int((duration % 3600) / 60)

        if duration == 0:
            self.ui.estimated_time_finish_label.setText("")
        elif duration < 60:
            self.ui.estimated_time_finish_label.setText(
                'Estimated time remaining: less than 1 minute')
        elif num_hour == 0:
            self.ui.estimated_time_finish_label.setText(
                f'Estimated time remaining: {num_minute} minute(s)')
        else:
            self.ui.estimated_time_finish_label.setText(
                f'Estimated time remaining: {num_hour} hour(s) {num_minute} minute(s)'
            )

    def open_preview_window(self, compulsory_list, optional_list):
        self.hide_error_message()
        self.preview_window.show()
        compulsory_text = self.get_compulsory_text(compulsory_list)
        optional_text = self.get_optional_text(optional_list)
        subject_preview, message_preview = self.logic.show_preview(
            compulsory_text, optional_text)
        self.preview_window.ui.subject_preview.setText(subject_preview)
        self.preview_window.ui.msg_preview.setText(message_preview)

    def switch_to_email_pg(self):
        self.ui.stackedWidget.setCurrentWidget(self.ui.mail_page)
        self.ui.label.setText("Send Email")

    def switch_to_status_pg(self):
        self.ui.stackedWidget.setCurrentWidget(self.ui.status_page)
        self.ui.label.setText("Send Status")

    def closeEvent(self, event):
        if self.logic.threadpool.activeThreadCount() > 0:
            button_clicked = self.ui.show_exit_confirmation()
            if button_clicked == QMessageBox.Yes:
                self.logger.info("User terminate program")
                self.close_window.show()
                self.hide()
                QApplication.processEvents()
                self.logic.kill_thread()
                while self.logic.threadpool.activeThreadCount() != 0:
                    QApplication.processEvents()
                self.close_window.close()
                event.accept()
            else:
                event.ignore()
        else:
            self.logger.info('Close program without active thread')
            event.accept()

    def update_progress_bar(self, progress):
        self.ui.progress_bar.setValue(progress)

    def show_sending_finish(self, num_success, num_fail):
        self.ui.send_btn.setEnabled(True)
        self.ui.status.moveCursor(QTextCursor.End)
        self.ui.status.insertHtml(
            ('<br>All emails sent!'
             '<br><b>Number of successful sends: {}'
             '<br>Number of fail sends: {}</b>'
             '<br>Failed emails saved as \'unsuccessful_emails.xlsx\' '
             'on Desktop').format(num_success, num_fail))
        self.ui.status.moveCursor(QTextCursor.End)

    def show_sending_start(self):
        self.ui.progress_bar.setValue(0)
        self.ui.send_btn.setDisabled(True)
        self.ui.status.setText('Sending emails...')
        self.ui.status_btn.click()
        self.ui.stackedWidget.setCurrentWidget(self.ui.status_page)

    def update_successful_status(self, email):
        self.ui.status.moveCursor(QTextCursor.End)
        self.ui.status.insertPlainText('\nsuccess: {}'.format(email))
        self.ui.status.moveCursor(QTextCursor.End)

    def update_fail_status(self, email):
        self.ui.status.moveCursor(QTextCursor.End)
        self.ui.status.insertPlainText('\nfail: {}'.format(email))
        self.ui.status.moveCursor(QTextCursor.End)

    def focus_on_attachment(self):
        position = self.ui.scrollArea.verticalScrollBar().maximum()
        self.ui.scrollArea.verticalScrollBar().setValue(position)
        # self.ui.scrollArea.verticalScrollBar().setValue(self.ui.attachment_grid.contentsRect().bottom())

    def truncate_email_label_text(self):
        email_label = os.path.basename(self.ui.receiver_file_label.text())
        label_width = self.ui.to_email_label.width()
        self.ui.to_email_label.setText(
            self.fm.elidedText(email_label, Qt.ElideRight, label_width))

    # def eventFilter(self, source, event):
    #     # adjust msg_entry height when it is resized by maximising or minimising window
    #     if event.type() == QEvent.Resize and source is self.ui.msg_entry:
    #         self.adjust_height()
    #     return super().eventFilter(source, event)

    # overrides resizeEvent of QMainWindow
    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.adjust_height()
        self.truncate_email_label_text()

    def adjust_slider(self):
        self.adjust_height()
        position = self.ui.msg_entry.cursorRect()
        # wait for 1 millisecond (for scroll bar height to re-adjust) before setting vertical scroll bar value
        QTimer.singleShot(
            1,
            partial(self.ui.scrollArea.ensureVisible, position.x(),
                    position.y(), 0, 30))
        # less ideal method
        # self.ui.scrollArea.verticalScrollBar().setValue(self.ui.msg_entry.cursorRect().top())

    def adjust_height(self):
        # expand height to remove scroll bar of QTextEdit
        height = self.ui.msg_entry.document().size().height()
        self.ui.msg_entry.setMinimumHeight(height)

    def get_compulsory_text(self, compulsory_list):
        compulsory_text = []
        for ele in compulsory_list:
            if isinstance(ele, QComboBox):
                compulsory_text.append(ele.currentText())
            else:
                compulsory_text.append(ele.text())
        return compulsory_text

    def get_optional_text(self, optional_list):
        optional_text = []
        for ele in optional_list:
            if isinstance(ele, QTextEdit):
                optional_text.append(ele.toPlainText())
            elif isinstance(ele, QComboBox):
                optional_text.append(ele.currentText())
            else:
                optional_text.append(ele.text())
        return optional_text

    def browse_file(self):
        receiver_file_name, _ = QFileDialog.getOpenFileName(
            self, 'Select A File',
            os.path.join(os.environ["HOMEPATH"], "Desktop"),
            "excel files (*.xlsx)")
        if not receiver_file_name:
            return
        self.model.receiver_file_name = receiver_file_name
        label_width = self.ui.to_email_label.width()
        self.ui.to_email_label.setText(
            self.fm.elidedText(
                receiver_file_name.split('/')[-1], Qt.ElideRight, label_width))
        self.ui.receiver_file_label.setText(receiver_file_name)
        receiver_df = pd.read_excel(receiver_file_name)
        self.update_combo_box(self.ui.email_column_combo, receiver_df.columns)
        self.update_combo_box(self.ui.personalised_att_combo,
                              receiver_df.columns)

    def update_combo_box(self, combo_box, column_names):
        if combo_box.count() > 1:
            for idx in range(combo_box.count() - 1, 0, -1):
                combo_box.removeItem(idx)

        combo_box.addItems(column_names)

    def attach_file(self):
        attach_file_name, _ = QFileDialog.getOpenFileName(
            self, 'Select A File',
            os.path.join(os.environ["HOMEPATH"], "Desktop"), "all files (*.*)")
        if not attach_file_name:
            return
        attachment_label = AttachmentLabel(attach_file_name)
        self.ui.attachment_grid.addWidget(attachment_label)
        # wait for 10 milliseconds (for scroll bar ui to update) before setting vertical scroll bar value
        QTimer.singleShot(10, self.focus_on_attachment)

    def hide_error_message(self):
        self.ui.email_address_error.setVisible(False)
        self.ui.no_password_error.setVisible(False)
        self.ui.to_error.setVisible(False)
        self.ui.invalid_col_error.setVisible(False)
        self.ui.invalid_byte_size_error.setVisible(False)

    def send_email(self, compulsory_list, optional_list, send_with_subject):
        self.hide_error_message()
        compulsory_text = self.get_compulsory_text(compulsory_list)
        optional_text = self.get_optional_text(optional_list)

        self.logic.send_email(compulsory_text, optional_text,
                              send_with_subject)

    def show_email_column_error(self):
        self.ui.invalid_col_error.show()

    def show_receiver_email_error(self):
        self.ui.to_error.show()

    def show_password_error(self):
        self.ui.no_password_error.show()
        self.ui.my_password_entry.setFocus()

    def show_my_email_error(self):
        self.ui.email_address_error.show()
        self.ui.my_email_entry.setFocus()

    def show_no_subject_pop_up(self, compulsory_list, optional_list):
        button_clicked = self.ui.show_no_subject_pop_up()
        if button_clicked == QMessageBox.Yes:
            self.send_email(compulsory_list, optional_list, False)
Exemplo n.º 10
0
def elide_text(label: QLabel, text: str):
    metrics = QFontMetrics(label.font())
    return metrics.elidedText(text, Qt.ElideRight, label.width())
Exemplo n.º 11
0
 def msg_signal_slot(self, msg: str):
     fontWidth = QFontMetrics(self.progress_msg.font())
     elideNote = fontWidth.elidedText(
         msg, Qt.ElideRight,
         self.name.width() + self.action.width() - 30)
     self.progress_msg.setText(elideNote)
Exemplo n.º 12
0
def elided(text, widget, width=None):
    metrix = QFontMetrics(widget.font())
    if width is None:
        width = widget.width()
    elided_text = metrix.elidedText(text, Qt.ElideMiddle, width)
    return elided_text