Example #1
1
class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.menu = ["Чизбургер", "Гамбургер", "Кока-кола", "Нагетсы"]
        self.initUI()

    def initUI(self):
        self.setGeometry(400, 300, 300, 400)
        self.setWindowTitle('Заказ в Макдональдсе')

        self.check_b = [QCheckBox(self) for i in self.menu]

        self.btn = QPushButton('Заказать', self)
        self.btn.clicked.connect(self.run)
        self.btn.move(10, 20 * (len(self.check_b) + 1))

        for i in range(len(self.check_b)):
            self.check_b[i].setText(self.menu[i])
            self.check_b[i].move(10, 20 * i)

        self.result = QPlainTextEdit(self)
        self.result.setEnabled(False)
        self.result.move(10, 20 * (len(self.check_b) + 3))

    def run(self):
        self.result.clear()
        result = [i.text() for i in self.check_b if i.isChecked()]
        result.insert(0, "Ваш заказ\n")

        self.result.appendPlainText("\n".join(result))
Example #2
0
class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.menu = ["Бургер", "Молочный коктель", "Картофель фри", "Нагецы", "Кока-кола", "Бигмак", "Чизбургер"]
        self.initUI()

    def initUI(self):
        self.setGeometry(400, 300, 300, 400)
        self.setWindowTitle('15_3')

        self.check_b = [QCheckBox(self) for i in self.menu]

        self.btn = QPushButton('Заказать', self)
        self.btn.clicked.connect(self.run)
        self.btn.move(10, 20 * (len(self.check_b) + 1))

        for i in range(len(self.check_b)):
            self.check_b[i].setText(self.menu[i])
            self.check_b[i].move(10,20*i)

        self.result = QPlainTextEdit(self)
        self.result.setEnabled(True)
        self.result.move(10,20*(len(self.check_b)+3))

    def run(self):
        self.result.clear()
        result = [i.text() for i in self.check_b if i.isChecked()]

        self.result.appendPlainText("\n".join(result))
Example #3
0
class BoxInfoCustom(QGroupBox):
    """ Clase con caja de información personalizada. """
    def __init__(self, title):
        QGroupBox.__init__(self, title)
        self.vbox = QVBoxLayout()
        self.textInfo = QPlainTextEdit()
        self.textInfo.setReadOnly(True)

        self.info = ""
        self.basic_styles = "font-size: 14px; color: black; font-weight: normal; font-family: Helvetica, Arial, sans-serif;"
        self.setInfo()
        self.setLayout(self.vbox)
        self.vbox.addWidget(self.textInfo)

    def updateBox(self, info=None, styles=None):
        self.info = "" if info is None else info
        self.basic_styles = self.basic_styles if styles is None else styles
        self.setInfo()

    def cleanBox(self):
        self.textInfo.clear()

    def setInfo(self):
        self.cleanBox()
        self.textInfo.insertPlainText(self.info)
        self.textInfo.setStyleSheet(self.basic_styles)
Example #4
0
class BarraHerramientasVentana(QMainWindow):
    def __init__(self):
        super().__init__()

        self.inicializarGui()

    def inicializarGui(self):
        self.setWindowTitle('Editor Básico de Texto')
        self.setFixedSize(400, 300)

        barra_herramientas = self.addToolBar('Archivo')

        mni_nuevo_archivo = QAction(QIcon('parte17/new.png'), 'Nuevo', self)
        mni_nuevo_archivo.triggered.connect(self.crear_archivo)
        barra_herramientas.addAction(mni_nuevo_archivo)

        mni_abrir_archivo = QAction(QIcon('parte17/open.png'), 'Abrir', self)
        mni_abrir_archivo.triggered.connect(self.abrir_archivo)
        barra_herramientas.addAction(mni_abrir_archivo)

        mni_guardar_archivo = QAction(QIcon('parte17/save.png'), 'Guardar',
                                      self)
        mni_guardar_archivo.triggered.connect(self.guardar_archivo)
        barra_herramientas.addAction(mni_guardar_archivo)

        self.contenido = QPlainTextEdit(self)
        self.contenido.move(10, 50)
        self.contenido.setFixedWidth(380)
        self.contenido.setFixedHeight(240)

    def crear_archivo(self):
        self.contenido.clear()

    def abrir_archivo(self):
        archivo, ok = QFileDialog.getOpenFileName(
            self, 'Seleccionar archivo de texto...', 'C:\\',
            'Archivo de texto (*.txt)')

        if ok:
            with open(archivo, 'r') as f:
                self.contenido.insertPlainText(''.join(f.readlines()))

    def guardar_archivo(self):
        archivo, ok = QFileDialog.getSaveFileName(
            self, 'Guardar archivo de texto...', 'C:\\',
            'Archivo de texto (*.txt)')

        if ok:
            with open(archivo, 'w') as f:
                f.write(self.contenido.toPlainText())
Example #5
0
class Example(QWidget):

    lst = []

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

        self.initUI()

    def initUI(self):

        self.setGeometry(480, 370, 480, 370)
        self.setWindowTitle('Заказ в Макдональдсе')

        self.te = QPlainTextEdit(self)
        self.te.move(200, 20)
        self.te.resize(250, 350)

        self.btn = QPushButton('Создать новый', self)
        self.btn.resize(160, 20)
        self.btn.move(20, 60)
        self.btn.clicked.connect(self.create_file)

        self.btn1 = QPushButton('Сохранить файл', self)
        self.btn1.resize(160, 20)
        self.btn1.move(20, 100)
        self.btn1.clicked.connect(self.end_work)

        self.btn2 = QPushButton('Открыть файл', self)
        self.btn2.resize(160, 20)
        self.btn2.move(20, 140)
        self.btn2.clicked.connect(self.open_file)

        self.le = QLineEdit(self)
        self.le.resize(160, 20)
        self.le.move(20, 20)

    def create_file(self):
        self.f = open(self.le.text(), 'w')

    def open_file(self):
        with open(self.le.text(), 'r') as f:
            text = f.read()
        self.te.appendPlainText(text)
        self.f = open(self.le.text(), 'w')

    def end_work(self):
        self.f.write(self.te.toPlainText())
        self.f.close()
        self.te.clear()
Example #6
0
class TextSubTab(QWidget):
    def __init__(self, sending=True):
        super(QWidget, self).__init__()
        layout = QHBoxLayout()
        self.text_message = QPlainTextEdit()
        self.text_message.setDisabled(not sending)
        layout.addWidget(self.text_message)
        self.setLayout(layout)

    def append_text_message(self, message):
        self.text_message.appendPlainText(message)

    def clear_text_message(self):
        self.text_message.clear()
class TopViewWindow(QWidget):
    closed = pyqtSignal()

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

        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()

        self.setWindowTitle(
            QtWidgets.QApplication.instance().applicationName() + ' - Top')

        self.text_box = QPlainTextEdit()
        self.text_box.setReadOnly(True)

        layout.addWidget(self.text_box)

        self.setLayout(layout)

        center_point = QDesktopWidget().availableGeometry().center()
        window_size = (800, 600)
        self.setGeometry(center_point.x() - window_size[0] // 2,
                         center_point.y() - window_size[1] // 2,
                         window_size[0], window_size[1])

        self.show()

        self.action_timer = QTimer(self)
        self.action_timer.setSingleShot(False)
        self.action_timer.setInterval(1000)
        self.action_timer.timeout.connect(self.update_data)
        self.action_timer.start(1000)

    def update_data(self):
        try:
            output = subprocess.run(["top", "-b", "-n1"], capture_output=True)
            self.text_box.clear()
            self.text_box.setPlainText(output.stdout)
        except (ValueError, OSError, subprocess.SubprocessError) as e:
            self.action_timer.stop()
            QMessageBox.critical(self, "Error!",
                                 f"Program execution error: {str(e)}",
                                 QMessageBox.Ok)

    def closeEvent(self, event):
        self.closed.emit()
        event.accept()
Example #8
0
class QPlainTextEditLogger(logging.Handler):
    def __init__(self, parent):
        super().__init__()
        self.messages = ''
        self.widget = QPlainTextEdit(parent)
        self.widget.setReadOnly(True)

    def emit(self, record):
        msg = self.format(record)
        self.messages += msg
        self.widget.appendPlainText(msg)

    def getTexttoFile(self):
        return self.widget.toPlainText()

    def deleteTextinGUI(self):
        self.widget.clear()
Example #9
0
class factorial_GUI(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Factorial')
        self.resize(500, 300)
        self.center()

        inputLabel = QLabel('Enter an integer')
        self.inputEdit = QLineEdit()
        clearButton = QPushButton('Clear')
        self.result = QPlainTextEdit('0')
        self.result.setReadOnly(True)

        grid = QGridLayout()
        grid.addWidget(inputLabel, 1, 0)
        grid.addWidget(self.inputEdit, 1, 1)
        grid.addWidget(clearButton, 2, 0)
        grid.addWidget(self.result, 2, 1)
        self.setLayout(grid)

        self.inputEdit.returnPressed.connect(self.onChanged)
        clearButton.clicked.connect(self.clear)
        self.show()

    def onChanged(self):
        val = self.inputEdit.text()
        try:
            r = factorial(int(val))
            r = format(r, ',')
            self.result.setPlainText(r)
        except:
            msg = '"%s" is not an integer' % (val)
            self.result.setPlainText(msg)

    def clear(self):
        self.inputEdit.clear()
        self.result.clear()

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
Example #10
0
class Focus(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(600, 400, 285, 310)
        self.setWindowTitle('Заказ в Макдональдсе')

        menu = ['Чизбургер', 'Кока-кола', 'Гамбургер', 'Нагетсы']
        r = []
        x = 10
        y = 10
        self.kt = []
        for i in range(4):
            r.append(i)
            r[i] = QCheckBox(menu[i], self)
            r[i].move(x, y)
            y += 17
            r[i].stateChanged.connect(self.conv)

        y += 10
        self.btn = QPushButton('Заказать', self)
        self.btn.move(x, y)
        self.btn.resize(90, 45)
        y += 60
        self.btn.clicked.connect(self.conv2)

        self.txt = QPlainTextEdit(self)
        self.txt.setGeometry(x, y, 100, 150)
        self.txt.setReadOnly(True)

    def conv(self, state):
        if state:
            self.kt.append(self.sender().text())
        else:
            self.kt.remove(self.sender().text())

    def conv2(self):
        self.txt.clear()
        if len(self.kt) > 0:
            self.txt.appendPlainText('Ваш заказ:')
            self.txt.appendPlainText('')
            for i in range(len(self.kt)):
                self.txt.appendPlainText(self.kt[i])
        else:
            self.txt.appendPlainText('Вы ничего не заказали :(')
Example #11
0
class QtLogging(logging.Handler):
    def __init__(self,parent, logger):
        super().__init__()
        self.widget = QDockWidget("Show log", parent)
        self._log_widget = QPlainTextEdit(self.widget)
        self._log_widget.setReadOnly(True)
        self.widget.setWidget(self._log_widget)
        self.records = []
        self.limit = 1000
        logger.addHandler(self)

    def emit(self, record):
        msg = self.format(record)
        if len(self.records) > self.limit:
            self.records = self.records[int(self.limit / 2):]
            self._log_widget.clear()
            self._log_widget.appendPlainText("\n".join(self.records))
        self.records.append(msg)
        self._log_widget.appendPlainText(msg)
Example #12
0
class InputTab(SerafinInputTab):
    def __init__(self, parent):
        super().__init__(parent)
        canvas = LineMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self.data = None
        self.mesh = None

        self.lines = []
        self.line_interpolators = []
        self.line_interpolators_internal = []  # without intersection points

        self._initWidgets()  # some instance attributes will be set there
        self._setLayout()
        self._bindEvents()

    def _initWidgets(self):
        # create the button open lines
        self.btnOpenLines = QPushButton('Load\nLines',
                                        self,
                                        icon=self.style().standardIcon(
                                            QStyle.SP_DialogOpenButton))
        self.btnOpenLines.setToolTip('<b>Open</b> a .i2s or .shp file')
        self.btnOpenLines.setFixedSize(105, 50)
        self.btnOpenLines.setEnabled(False)

        # create some text fields displaying the IO files info
        self.linesNameBox = QPlainTextEdit()
        self.linesNameBox.setReadOnly(True)
        self.linesNameBox.setFixedHeight(50)

        # create the map button
        self.btnMap = QPushButton('Locate lines\non map',
                                  self,
                                  icon=self.style().standardIcon(
                                      QStyle.SP_DialogHelpButton))
        self.btnMap.setFixedSize(135, 50)
        self.btnMap.setEnabled(False)

    def _bindEvents(self):
        self.btnOpen.clicked.connect(self.btnOpenSerafinEvent)
        self.btnOpenLines.clicked.connect(self.btnOpenLinesEvent)
        self.btnMap.clicked.connect(self.btnMapEvent)

    def _setLayout(self):
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.setSpacing(15)
        hlayout = QHBoxLayout()
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.setAlignment(Qt.AlignLeft)
        hlayout.addWidget(self.btnOpen)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.langBox)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.btnOpenLines)
        hlayout.addWidget(self.btnMap)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('     Input file'), 1, 1)
        glayout.addWidget(self.inNameBox, 1, 2)
        glayout.addWidget(QLabel('     Summary'), 2, 1)
        glayout.addWidget(self.summaryTextBox, 2, 2)
        glayout.addWidget(QLabel('     Lines file'), 3, 1)
        glayout.addWidget(self.linesNameBox, 3, 2)
        glayout.setAlignment(Qt.AlignLeft)
        glayout.setSpacing(10)
        mainLayout.addLayout(glayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        mainLayout.addWidget(QLabel('   Message logs'))
        mainLayout.addWidget(self.logTextBox.widget)
        self.setLayout(mainLayout)

    def _reinitInput(self):
        self.reset()
        self.data = None
        self.has_map = False
        self.btnMap.setEnabled(False)
        self.mesh = None
        self.btnOpenLines.setEnabled(False)
        self.parent.reset()

    def _resetDefaultOptions(self):
        nb_nonempty = 0

        self.line_interpolators = []
        self.line_interpolators_internal = []

        for line in self.lines:
            line_interpolators, distances, \
                line_interpolators_internal, distances_internal = self.mesh.get_line_interpolators(line)
            if line_interpolators:
                nb_nonempty += 1
            self.line_interpolators.append((line_interpolators, distances))
            self.line_interpolators_internal.append(
                (line_interpolators_internal, distances_internal))

        if nb_nonempty == 0:
            self.lines = []
            self.line_interpolators = []
            self.line_interpolators_internal = []

            self.linesNameBox.clear()
            self.parent.reset()

        else:
            old_filename = self.linesNameBox.toPlainText().split('\n')[0]
            self.linesNameBox.clear()
            self.linesNameBox.appendPlainText(
                old_filename + '\n' + 'The file contains {} open polyline{}.'
                '{} line{} the mesh continuously.'.format(
                    len(self.lines), 's' if len(self.lines) > 1 else '',
                    nb_nonempty,
                    's intersect' if nb_nonempty > 1 else ' intersects'))

            self.has_map = False
            self.btnMap.setEnabled(True)
            self.parent.getInput()

    def btnOpenSerafinEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitInput()
        success, data = self.read_2d(filename)
        if not success:
            return

        # record the mesh for future visualization and calculations
        self.parent.inDialog()
        meshLoader = LoadMeshDialog('interpolation', data.header)
        self.mesh = meshLoader.run()
        self.parent.outDialog()
        if meshLoader.thread.canceled:
            self.linesNameBox.clear()
            self.parent.reset()
            return

        self.data = data
        self.btnOpenLines.setEnabled(True)
        self._resetDefaultOptions()

    def btnOpenLinesEvent(self):
        success, filename, polylines = open_polylines()
        if not success:
            return
        self.lines = polylines
        logging.info('Finished reading the lines file %s' % filename)

        nb_nonempty, indices_nonempty, \
            self.line_interpolators, self.line_interpolators_internal = self.mesh.get_line_interpolators(self.lines)

        if nb_nonempty == 0:
            QMessageBox.critical(self, 'Error',
                                 'No line intersects the mesh continuously.',
                                 QMessageBox.Ok)
            return

        logging.info('Finished reading the lines file %s' % filename)

        self.linesNameBox.clear()
        self.linesNameBox.appendPlainText(
            filename + '\n' + 'The file contains {} open polyline{}.'
            '{} line{} the mesh continuously.'.format(
                len(self.lines), 's' if len(self.lines) > 1 else '',
                nb_nonempty,
                's intersect' if nb_nonempty > 1 else ' intersects'))

        self.has_map = False
        self.btnMap.setEnabled(True)
        self.parent.getInput()

    def btnMapEvent(self):
        if not self.has_map:
            self.map.canvas.reinitFigure(
                self.mesh, self.lines, [poly.id for poly in self.lines],
                list(
                    islice(
                        cycle(['b', 'r', 'g', 'y', 'k', 'c', '#F28AD6', 'm']),
                        len(self.lines))))

            self.has_map = True

            self.map.canvas.draw()
            self.has_map = True
        self.map.show()
class CLIWidget(QWidget):
    def __init__(self, parent, cli_iface):
        super(CLIWidget, self).__init__(parent)

        self._cli_iface = cli_iface

        self._command_line = CommitableComboBoxWithHistory(self)
        self._command_line.setToolTip('Enter the command here')
        self._command_line.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self._command_line.setFont(get_monospace_font())
        self._command_line.on_commit = self._do_execute

        self._command_line_completer = QCompleter()
        self._command_line_completer.setCaseSensitivity(Qt.CaseSensitive)
        self._command_line_completer.setModel(self._command_line.model())

        self._command_line.setCompleter(self._command_line_completer)

        self._execute_button = make_icon_button('flash', 'Execute command', self, on_clicked=self._do_execute)

        self._response_box = QPlainTextEdit(self)
        self._response_box.setToolTip('Command output will be printed here')
        self._response_box.setReadOnly(True)
        self._response_box.setLineWrapMode(QPlainTextEdit.NoWrap)
        self._response_box.setFont(get_monospace_font())
        self._response_box.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        try:
            self._log_viewer.setPlaceholderText('Command output will be printed here')
        except AttributeError:      # Old PyQt
            pass

        layout = QVBoxLayout(self)

        controls_layout = QHBoxLayout(self)
        controls_layout.addWidget(self._command_line, 1)
        controls_layout.addWidget(self._execute_button)

        layout.addLayout(controls_layout)
        layout.addWidget(self._response_box, 1)
        self.setLayout(layout)

    def _do_execute(self):
        self._response_box.clear()

        command = self._command_line.currentText()
        if not command.strip():
            return

        self._command_line.add_current_text_to_history()

        def callback(lines):
            self.setEnabled(True)
            if lines is None:
                self.window().show_message('Command response timed out')
                self._response_box.setPlainText('<RESPONSE TIMED OUT>')
            else:
                self.window().show_message('Command response received')
                self._response_box.setPlainText(lines)

        self.setEnabled(False)
        self._cli_iface.execute_raw_command(command, callback)
class comic_meta_data_editor(QDialog):
    configGroup = "ComicsProjectManagementTools"

    # Translatable genre dictionary that has it's translated entries added to the genrelist and from which the untranslated items are taken.
    acbfGenreList = {"science_fiction": str(i18n("Science Fiction")), "fantasy": str(i18n("Fantasy")), "adventure": str(i18n("Adventure")), "horror": str(i18n("Horror")), "mystery": str(i18n("Mystery")), "crime": str(i18n("Crime")), "military": str(i18n("Military")), "real_life": str(i18n("Real Life")), "superhero": str(i18n("Superhero")), "humor": str(i18n("Humor")), "western": str(i18n("Western")), "manga": str(i18n("Manga")), "politics": str(i18n("Politics")), "caricature": str(i18n("Caricature")), "sports": str(i18n("Sports")), "history": str(i18n("History")), "biography": str(i18n("Biography")), "education": str(i18n("Education")), "computer": str(i18n("Computer")), "religion": str(i18n("Religion")), "romance": str(i18n("Romance")), "children": str(i18n("Children")), "non-fiction": str(i18n("Non Fiction")), "adult": str(i18n("Adult")), "alternative": str(i18n("Alternative")), "artbook": str(i18n("Artbook")), "other": str(i18n("Other"))}
    acbfAuthorRolesList = {"Writer": str(i18n("Writer")), "Adapter": str(i18n("Adapter")), "Artist": str(i18n("Artist")), "Penciller": str(i18n("Penciller")), "Inker": str(i18n("Inker")), "Colorist": str(i18n("Colorist")), "Letterer": str(i18n("Letterer")), "Cover Artist": str(i18n("Cover Artist")), "Photographer": str(i18n("Photographer")), "Editor": str(i18n("Editor")), "Assistant Editor": str(i18n("Assistant Editor")), "Designer": str(i18n("Designer")), "Translator": str(i18n("Translator")), "Other": str(i18n("Other"))}

    def __init__(self):
        super().__init__()
        # Get the keys for the autocompletion.
        self.genreKeysList = []
        self.characterKeysList = []
        self.ratingKeysList = {}
        self.formatKeysList = []
        self.otherKeysList = []
        self.authorRoleList = []
        for g in self.acbfGenreList.values():
            self.genreKeysList.append(g)
        for r in self.acbfAuthorRolesList.values():
            self.authorRoleList.append(r)
        mainP = Path(os.path.abspath(__file__)).parent
        self.get_auto_completion_keys(mainP)
        extraKeyP = Path(QDir.homePath()) / Application.readSetting(self.configGroup, "extraKeysLocation", str())
        self.get_auto_completion_keys(extraKeyP)

        # Setup the dialog.
        self.setLayout(QVBoxLayout())
        mainWidget = QTabWidget()
        self.layout().addWidget(mainWidget)
        self.setWindowTitle(i18n("Comic Metadata"))
        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.layout().addWidget(buttons)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

        # Title, concept, summary, genre, characters, format, rating, language, series, other keywords
        metadataPage = QWidget()
        mformLayout = QFormLayout()
        metadataPage.setLayout(mformLayout)

        self.lnTitle = QLineEdit()
        self.lnTitle.setToolTip(i18n("The proper title of the comic."))

        self.teSummary = QPlainTextEdit()
        self.teSummary.setToolTip(i18n("What will you tell others to entice them to read your comic?"))

        self.lnGenre = QLineEdit()
        genreCompletion = multi_entry_completer()
        genreCompletion.setModel(QStringListModel(self.genreKeysList))
        self.lnGenre.setCompleter(genreCompletion)
        genreCompletion.setCaseSensitivity(False)
        self.lnGenre.setToolTip(i18n("The genre of the work. Prefilled values are from the ACBF, but you can fill in your own. Separate genres with commas. Try to limit the amount to about two or three."))

        self.lnCharacters = QLineEdit()
        characterCompletion = multi_entry_completer()
        characterCompletion.setModel(QStringListModel(self.characterKeysList))
        characterCompletion.setCaseSensitivity(False)
        characterCompletion.setFilterMode(Qt.MatchContains)  # So that if there is a list of names with last names, people can type in a last name.
        self.lnCharacters.setCompleter(characterCompletion)
        self.lnCharacters.setToolTip(i18n("The names of the characters that this comic revolves around. Comma-separated."))

        self.lnFormat = QLineEdit()
        formatCompletion = multi_entry_completer()
        formatCompletion.setModel(QStringListModel(self.formatKeysList))
        formatCompletion.setCaseSensitivity(False)
        self.lnFormat.setCompleter(formatCompletion)

        ratingLayout = QHBoxLayout()
        self.cmbRatingSystem = QComboBox()
        self.cmbRatingSystem.addItems(self.ratingKeysList.keys())
        self.cmbRatingSystem.setEditable(True)
        self.cmbRating = QComboBox()
        self.cmbRating.setEditable(True)
        self.cmbRatingSystem.currentIndexChanged.connect(self.slot_refill_ratings)
        ratingLayout.addWidget(self.cmbRatingSystem)
        ratingLayout.addWidget(self.cmbRating)

        self.lnSeriesName = QLineEdit()
        self.lnSeriesName.setToolTip(i18n("If this is part of a series, enter the name of the series and the number."))
        self.spnSeriesNumber = QSpinBox()
        self.spnSeriesNumber.setPrefix(i18n("No. "))
        self.spnSeriesVol = QSpinBox()
        self.spnSeriesVol.setPrefix(i18n("Vol. "))
        seriesLayout = QHBoxLayout()
        seriesLayout.addWidget(self.lnSeriesName)
        seriesLayout.addWidget(self.spnSeriesVol)
        seriesLayout.addWidget(self.spnSeriesNumber)

        otherCompletion = multi_entry_completer()
        otherCompletion.setModel(QStringListModel(self.otherKeysList))
        otherCompletion.setCaseSensitivity(False)
        otherCompletion.setFilterMode(Qt.MatchContains)
        self.lnOtherKeywords = QLineEdit()
        self.lnOtherKeywords.setCompleter(otherCompletion)
        self.lnOtherKeywords.setToolTip(i18n("Other keywords that do not fit in the previously mentioned sets. As always, comma-separated."))

        self.cmbLanguage = language_combo_box()
        self.cmbCountry = country_combo_box()
        self.cmbLanguage.currentIndexChanged.connect(self.slot_update_countries)
        self.cmbReadingMode = QComboBox()
        self.cmbReadingMode.addItem(i18n("Left to Right"))
        self.cmbReadingMode.addItem(i18n("Right to Left"))

        self.cmbCoverPage = QComboBox()
        self.cmbCoverPage.setToolTip(i18n("Which page is the cover page? This will be empty if there are no pages."))

        mformLayout.addRow(i18n("Title:"), self.lnTitle)
        mformLayout.addRow(i18n("Cover page:"), self.cmbCoverPage)
        mformLayout.addRow(i18n("Summary:"), self.teSummary)
        mformLayout.addRow(i18n("Language:"), self.cmbLanguage)
        mformLayout.addRow("", self.cmbCountry)
        mformLayout.addRow(i18n("Reading direction:"), self.cmbReadingMode)
        mformLayout.addRow(i18n("Genre:"), self.lnGenre)
        mformLayout.addRow(i18n("Characters:"), self.lnCharacters)
        mformLayout.addRow(i18n("Format:"), self.lnFormat)
        mformLayout.addRow(i18n("Rating:"), ratingLayout)
        mformLayout.addRow(i18n("Series:"), seriesLayout)
        mformLayout.addRow(i18n("Other:"), self.lnOtherKeywords)

        mainWidget.addTab(metadataPage, i18n("Work"))

        # The page for the authors.
        authorPage = QWidget()
        authorPage.setLayout(QVBoxLayout())
        explanation = QLabel(i18n("The following is a table of the authors that contributed to this comic. You can set their nickname, proper names (first, middle, last), role (penciller, inker, etc), email and homepage."))
        explanation.setWordWrap(True)
        self.authorModel = QStandardItemModel(0, 8)
        labels = [i18n("Nick Name"), i18n("Given Name"), i18n("Middle Name"), i18n("Family Name"), i18n("Role"), i18n("Email"), i18n("Homepage"), i18n("Language")]
        self.authorModel.setHorizontalHeaderLabels(labels)
        self.authorTable = QTableView()
        self.authorTable.setModel(self.authorModel)
        self.authorTable.verticalHeader().setDragEnabled(True)
        self.authorTable.verticalHeader().setDropIndicatorShown(True)
        self.authorTable.verticalHeader().setSectionsMovable(True)
        self.authorTable.verticalHeader().sectionMoved.connect(self.slot_reset_author_row_visual)
        delegate = author_delegate()
        delegate.setCompleterData(self.authorRoleList, 4)
        delegate.setLanguageData(len(labels) - 1)
        self.authorTable.setItemDelegate(delegate)
        author_button_layout = QWidget()
        author_button_layout.setLayout(QHBoxLayout())
        btn_add_author = QPushButton(i18n("Add Author"))
        btn_add_author.clicked.connect(self.slot_add_author)
        btn_remove_author = QPushButton(i18n("Remove Author"))
        btn_remove_author.clicked.connect(self.slot_remove_author)
        author_button_layout.layout().addWidget(btn_add_author)
        author_button_layout.layout().addWidget(btn_remove_author)
        authorPage.layout().addWidget(explanation)
        authorPage.layout().addWidget(self.authorTable)
        authorPage.layout().addWidget(author_button_layout)
        mainWidget.addTab(authorPage, i18n("Authors"))

        # The page with publisher information.
        publisherPage = QWidget()
        publisherLayout = QFormLayout()
        publisherPage.setLayout(publisherLayout)
        self.publisherName = QLineEdit()
        self.publisherName.setToolTip(i18n("The name of the company, group or person who is responsible for the final version the reader gets."))
        publishDateLayout = QHBoxLayout()
        self.publishDate = QDateEdit()
        self.publishDate.setDisplayFormat(QLocale().system().dateFormat())
        currentDate = QPushButton(i18n("Set Today"))
        currentDate.setToolTip(i18n("Sets the publish date to the current date."))
        currentDate.clicked.connect(self.slot_set_date)
        publishDateLayout.addWidget(self.publishDate)
        publishDateLayout.addWidget(currentDate)
        self.publishCity = QLineEdit()
        self.publishCity.setToolTip(i18n("Traditional publishers are always mentioned in source with the city they are located."))
        self.isbn = QLineEdit()
        self.license = license_combo_box()  # Maybe ought to make this a QLineEdit...
        self.license.setEditable(True)
        self.license.completer().setCompletionMode(QCompleter.PopupCompletion)
        dataBaseReference = QVBoxLayout()
        self.ln_database_name = QLineEdit()
        self.ln_database_name.setToolTip(i18n("If there is an entry in a comics data base, that should be added here. It is unlikely to be a factor for comics from scratch, but useful when doing a conversion."))
        self.cmb_entry_type = QComboBox()
        self.cmb_entry_type.addItems(["IssueID", "SeriesID", "URL"])
        self.cmb_entry_type.setEditable(True)
        self.ln_source = QLineEdit()
        self.ln_source.setToolTip(i18n("Whether the comic is an adaptation of an existing source, and if so, how to find information about that source. So for example, for an adapted webcomic, the official website url should go here."))
        self.label_uuid = QLabel()
        self.label_uuid.setToolTip(i18n("By default this will be filled with a generated universal unique identifier. The ID by itself is merely so that comic book library management programs can figure out if this particular comic is already in their database and whether it has been rated. Of course, the UUID can be changed into something else by manually changing the JSON, but this is advanced usage."))
        self.ln_database_entry = QLineEdit()
        dbHorizontal = QHBoxLayout()
        dbHorizontal.addWidget(self.ln_database_name)
        dbHorizontal.addWidget(self.cmb_entry_type)
        dataBaseReference.addLayout(dbHorizontal)
        dataBaseReference.addWidget(self.ln_database_entry)
        publisherLayout.addRow(i18n("Name:"), self.publisherName)
        publisherLayout.addRow(i18n("City:"), self.publishCity)
        publisherLayout.addRow(i18n("Date:"), publishDateLayout)
        publisherLayout.addRow(i18n("ISBN:"), self.isbn)
        publisherLayout.addRow(i18n("Source:"), self.ln_source)
        publisherLayout.addRow(i18n("UUID:"), self.label_uuid)
        publisherLayout.addRow(i18n("License:"), self.license)
        publisherLayout.addRow(i18n("Database:"), dataBaseReference)

        mainWidget.addTab(publisherPage, i18n("Publisher"))
    """
    Ensure that the drag and drop of authors doesn't mess up the labels.
    """

    def slot_reset_author_row_visual(self):
        headerLabelList = []
        for i in range(self.authorTable.verticalHeader().count()):
            headerLabelList.append(str(i))
        for i in range(self.authorTable.verticalHeader().count()):
            logicalI = self.authorTable.verticalHeader().logicalIndex(i)
            headerLabelList[logicalI] = str(i + 1)
        self.authorModel.setVerticalHeaderLabels(headerLabelList)
    """
    Set the publish date to the current date.
    """

    def slot_set_date(self):
        self.publishDate.setDate(QDate().currentDate())
        
    def slot_update_countries(self):
        code = self.cmbLanguage.codeForCurrentEntry()
        self.cmbCountry.set_country_for_locale(code)

    """
    Append keys to autocompletion lists from the directory mainP.
    """

    def get_auto_completion_keys(self, mainP=Path()):
        genre = Path(mainP / "key_genre")
        characters = Path(mainP / "key_characters")
        rating = Path(mainP / "key_rating")
        format = Path(mainP / "key_format")
        keywords = Path(mainP / "key_other")
        authorRole = Path(mainP / "key_author_roles")
        if genre.exists():
            for t in list(genre.glob('**/*.txt')):
                file = open(str(t), "r", errors="replace")
                for l in file:
                    if str(l).strip("\n") not in self.genreKeysList:
                        self.genreKeysList.append(str(l).strip("\n"))
                file.close()
        if characters.exists():
            for t in list(characters.glob('**/*.txt')):
                file = open(str(t), "r", errors="replace")
                for l in file:
                    if str(l).strip("\n") not in self.characterKeysList:
                        self.characterKeysList.append(str(l).strip("\n"))
                file.close()
        if format.exists():
            for t in list(format.glob('**/*.txt')):
                file = open(str(t), "r", errors="replace")
                for l in file:
                    if str(l).strip("\n") not in self.formatKeysList:
                        self.formatKeysList.append(str(l).strip("\n"))
                file.close()
        if rating.exists():
            for t in list(rating.glob('**/*.csv')):
                file = open(str(t), "r", newline="", encoding="utf-8")
                ratings = csv.reader(file)
                title = os.path.basename(str(t))
                r = 0
                for row in ratings:
                    listItem = []
                    if r is 0:
                        title = row[1]
                    else:
                        listItem = self.ratingKeysList[title]
                        item = []
                        item.append(row[0])
                        item.append(row[1])
                        listItem.append(item)
                    self.ratingKeysList[title] = listItem
                    r += 1
                file.close()
        if keywords.exists():
            for t in list(keywords.glob('**/*.txt')):
                file = open(str(t), "r", errors="replace")
                for l in file:
                    if str(l).strip("\n") not in self.otherKeysList:
                        self.otherKeysList.append(str(l).strip("\n"))
                file.close()
        if authorRole.exists():
            for t in list(authorRole.glob('**/*.txt')):
                file = open(str(t), "r", errors="replace")
                for l in file:
                    if str(l).strip("\n") not in self.authorRoleList:
                        self.authorRoleList.append(str(l).strip("\n"))
                file.close()

    """
    Refill the ratings box.
    This is called whenever the rating system changes.
    """

    def slot_refill_ratings(self):
        if self.cmbRatingSystem.currentText() in self.ratingKeysList.keys():
            self.cmbRating.clear()
            model = QStandardItemModel()
            for i in self.ratingKeysList[self.cmbRatingSystem.currentText()]:
                item = QStandardItem()
                item.setText(i[0])
                item.setToolTip(i[1])
                model.appendRow(item)
            self.cmbRating.setModel(model)

    """
    Add an author with default values initialised.
    """

    def slot_add_author(self):
        listItems = []
        listItems.append(QStandardItem(i18n("Anon")))  # Nick name
        listItems.append(QStandardItem(i18n("John")))  # First name
        listItems.append(QStandardItem())  # Middle name
        listItems.append(QStandardItem(i18n("Doe")))  # Last name
        listItems.append(QStandardItem())  # role
        listItems.append(QStandardItem())  # email
        listItems.append(QStandardItem())  # homepage
        language = QLocale.system().name().split("_")[0]
        if language == "C":
            language = "en"
        listItems.append(QStandardItem(language))  # Language
        self.authorModel.appendRow(listItems)

    """
    Remove the selected author from the author list.
    """

    def slot_remove_author(self):
        self.authorModel.removeRow(self.authorTable.currentIndex().row())

    """
    Load the UI values from the config dictionary given.
    """

    def setConfig(self, config):

        if "title" in config.keys():
            self.lnTitle.setText(config["title"])
        self.teSummary.clear()
        if "pages" in config.keys():
            self.cmbCoverPage.clear()
            for page in config["pages"]:
                self.cmbCoverPage.addItem(page)
            if "cover" in config.keys():
                if config["cover"] in config["pages"]:
                    self.cmbCoverPage.setCurrentText(config["cover"])
        if "summary" in config.keys():
            self.teSummary.appendPlainText(config["summary"])
        if "genre" in config.keys():
            genreList = []
            genreListConf = config["genre"]
            totalMatch = 100
            if isinstance(config["genre"], dict):
                genreListConf = config["genre"].keys()
                totalMatch = 0
            for genre in genreListConf:
                genreKey = genre
                if genre in self.acbfGenreList:
                    genreKey = self.acbfGenreList[genre]
                if isinstance(config["genre"], dict):
                    genreValue = config["genre"][genre]
                    if genreValue > 0:
                        genreKey = str(genreKey + "(" + str(genreValue) + ")")
                genreList.append(genreKey)
            self.lnGenre.setText(", ".join(genreList))
        if "characters" in config.keys():
            self.lnCharacters.setText(", ".join(config["characters"]))
        if "format" in config.keys():
            self.lnFormat.setText(", ".join(config["format"]))
        if "rating" in config.keys():
            self.cmbRating.setCurrentText(config["rating"])
        else:
            self.cmbRating.setCurrentText("")
        if "ratingSystem" in config.keys():
            self.cmbRatingSystem.setCurrentText(config["ratingSystem"])
        else:
            self.cmbRatingSystem.setCurrentText("")
        if "otherKeywords" in config.keys():
            self.lnOtherKeywords.setText(", ".join(config["otherKeywords"]))
        if "seriesName" in config.keys():
            self.lnSeriesName.setText(config["seriesName"])
        if "seriesVolume" in config.keys():
            self.spnSeriesVol.setValue(config["seriesVolume"])
        if "seriesNumber" in config.keys():
            self.spnSeriesNumber.setValue(config["seriesNumber"])
        if "language" in config.keys():
            code = config["language"]
            if "_" in code:
                self.cmbLanguage.setEntryToCode(code.split("_")[0])
                self.cmbCountry.setEntryToCode(code.split("_")[-1])
            elif "-" in code:
                self.cmbLanguage.setEntryToCode(code.split("-")[0])
                self.cmbCountry.setEntryToCode(code.split("-")[-1])
            else:
                self.cmbLanguage.setEntryToCode(code)
        if "readingDirection" in config.keys():
            if config["readingDirection"] is "leftToRight":
                self.cmbReadingMode.setCurrentIndex(int(Qt.LeftToRight))
            else:
                self.cmbReadingMode.setCurrentIndex(int(Qt.RightToLeft))
        else:
            self.cmbReadingMode.setCurrentIndex(QLocale(self.cmbLanguage.codeForCurrentEntry()).textDirection())
        if "publisherName" in config.keys():
            self.publisherName.setText(config["publisherName"])
        if "publisherCity" in config.keys():
            self.publishCity.setText(config["publisherCity"])
        if "publishingDate" in config.keys():
            self.publishDate.setDate(QDate.fromString(config["publishingDate"], Qt.ISODate))
        if "isbn-number" in config.keys():
            self.isbn.setText(config["isbn-number"])
        if "source" in config.keys():
            self.ln_source.setText(config["source"])
        elif "acbfSource" in config.keys():
            self.ln_source.setText(config["acbfSource"])
        if "uuid" in config.keys():
            self.label_uuid.setText(config["uuid"])
        else:
            uuid = str()
            if "acbfID" in config.keys():
                uuid = config["acbfID"]
                uuid = uuid.strip("{")
                uuid = uuid.strip("}")
                uuidVerify = uuid.split("-")
                if len(uuidVerify[0])!=8 or len(uuidVerify[1])!=4 or len(uuidVerify[2])!=4 or len(uuidVerify[3])!=4 or len(uuidVerify[4])!=12:
                    uuid = QUuid.createUuid().toString()
            self.label_uuid.setText(uuid)
            config["uuid"] = uuid
        if "license" in config.keys():
            self.license.setCurrentText(config["license"])
        else:
            self.license.setCurrentText("")  # I would like to keep it ambiguous whether the artist has thought about the license or not.
        if "authorList" in config.keys():
            authorList = config["authorList"]
            for i in range(len(authorList)):
                author = authorList[i]
                if len(author.keys()) > 0:
                    listItems = []
                    listItems = []
                    listItems.append(QStandardItem(author.get("nickname", "")))
                    listItems.append(QStandardItem(author.get("first-name", "")))
                    listItems.append(QStandardItem(author.get("initials", "")))
                    listItems.append(QStandardItem(author.get("last-name", "")))
                    role = author.get("role", "")
                    if role in self.acbfAuthorRolesList.keys():
                        role = self.acbfAuthorRolesList[role]
                    listItems.append(QStandardItem(role))
                    listItems.append(QStandardItem(author.get("email", "")))
                    listItems.append(QStandardItem(author.get("homepage", "")))
                    listItems.append(QStandardItem(author.get("language", "")))
                    self.authorModel.appendRow(listItems)
        else:
            self.slot_add_author()
        dbRef = config.get("databaseReference", {})
        self.ln_database_name.setText(dbRef.get("name", ""))
        self.ln_database_entry.setText(dbRef.get("entry", ""))
        stringCmbEntryType = self.cmb_entry_type.itemText(0)
        self.cmb_entry_type.setCurrentText(dbRef.get("type", stringCmbEntryType))

    """
    Store the GUI values into the config dictionary given.
    
    @return the config diactionary filled with new values.
    """

    def getConfig(self, config):

        text = self.lnTitle.text()
        if len(text) > 0 and text.isspace() is False:
            config["title"] = text
        elif "title" in config.keys():
            config.pop("title")
        config["cover"] = self.cmbCoverPage.currentText()
        listkeys = self.lnGenre.text()
        if len(listkeys) > 0 and listkeys.isspace() is False:
            preSplit = self.lnGenre.text().split(",")
            genreMatcher = re.compile(r'\((\d+)\)')
            genreList = {}
            totalValue = 0
            for key in preSplit:
                m = genreMatcher.search(key)
                if m:
                    genre = str(genreMatcher.sub("", key)).strip()
                    match = int(m.group()[:-1][1:])
                else:
                    genre = key.strip()
                    match = 0
                if genre in self.acbfGenreList.values():
                    i = list(self.acbfGenreList.values()).index(genre)
                    genreList[list(self.acbfGenreList.keys())[i]] = match
                else:
                    genreList[genre] = match
                totalValue += match
            # Normalize the values:
            for key in genreList.keys():
                if genreList[key] > 0:
                    genreList[key] = round(genreList[key] / totalValue * 100)
            config["genre"] = genreList
        elif "genre" in config.keys():
            config.pop("genre")
        listkeys = self.lnCharacters.text()
        if len(listkeys) > 0 and listkeys.isspace() is False:
            config["characters"] = self.lnCharacters.text().split(", ")
        elif "characters" in config.keys():
            config.pop("characters")
        listkeys = self.lnFormat.text()
        if len(listkeys) > 0 and listkeys.isspace() is False:
            config["format"] = self.lnFormat.text().split(", ")
        elif "format" in config.keys():
            config.pop("format")
        config["ratingSystem"] = self.cmbRatingSystem.currentText()
        config["rating"] = self.cmbRating.currentText()
        listkeys = self.lnOtherKeywords.text()
        if len(listkeys) > 0 and listkeys.isspace() is False:
            config["otherKeywords"] = self.lnOtherKeywords.text().split(", ")
        elif "otherKeywords" in config.keys():
            config.pop("otherKeywords")
        text = self.teSummary.toPlainText()
        if len(text) > 0 and text.isspace() is False:
            config["summary"] = text
        elif "summary" in config.keys():
            config.pop("summary")
        if len(self.lnSeriesName.text()) > 0:
            config["seriesName"] = self.lnSeriesName.text()
            config["seriesNumber"] = self.spnSeriesNumber.value()
            if self.spnSeriesVol.value() > 0:
                config["seriesVolume"] = self.spnSeriesVol.value()
        config["language"] = str(self.cmbLanguage.codeForCurrentEntry()+"-"+self.cmbCountry.codeForCurrentEntry())
        if self.cmbReadingMode.currentIndex() is int(Qt.LeftToRight):
            config["readingDirection"] = "leftToRight"
        else:
            config["readingDirection"] = "rightToLeft"
        authorList = []
        for row in range(self.authorTable.verticalHeader().count()):
            logicalIndex = self.authorTable.verticalHeader().logicalIndex(row)
            listEntries = ["nickname", "first-name", "initials", "last-name", "role", "email", "homepage", "language"]
            author = {}
            for i in range(len(listEntries)):
                entry = self.authorModel.data(self.authorModel.index(logicalIndex, i))
                if entry is None:
                    entry = " "
                if entry.isspace() is False and len(entry) > 0:
                    if listEntries[i] == "role":
                        if entry in self.acbfAuthorRolesList.values():
                            entryI = list(self.acbfAuthorRolesList.values()).index(entry)
                            entry = list(self.acbfAuthorRolesList.keys())[entryI]
                    author[listEntries[i]] = entry
                elif listEntries[i] in author.keys():
                    author.pop(listEntries[i])
            authorList.append(author)
        config["authorList"] = authorList
        config["publisherName"] = self.publisherName.text()
        config["publisherCity"] = self.publishCity.text()
        config["publishingDate"] = self.publishDate.date().toString(Qt.ISODate)
        config["isbn-number"] = self.isbn.text()
        config["source"] = self.ln_source.text()
        config["license"] = self.license.currentText()
        if self.ln_database_name.text().isalnum() and self.ln_database_entry.text().isalnum():
            dbRef = {}
            dbRef["name"] = self.ln_database_name.text()
            dbRef["entry"] = self.ln_database_entry.text()
            dbRef["type"] = self.cmb_entry_type.currentText()
            config["databaseReference"] = dbRef

        return config
class MainWindow(QMainWindow, Ui_MainWindow):
    # Maintain the list of browser windows so that they do not get garbage
    # collected.
    _window_list = []

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

        MainWindow._window_list.append(self)

        self.setupUi(self)

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

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

        self.pb = QProgressBar(self.statusBar())
        self.pb.setTextVisible(False)
        self.pb.hide()
        self.statusBar().addPermanentWidget(self.pb)
        self.WebBrowser.dynamicCall('GoHome()')
        self.setWindowTitle("PyQt messagebox example - pythonprogramminglanguage.com") 

        self.text_box = QPlainTextEdit(self)
        self.text_box.insertPlainText("You can write text here.\n")
        self.text_box.move(950,910)
        self.text_box.resize(300,80)
    
    def closeEvent(self, e):
        MainWindow._window_list.remove(self)
        e.accept()

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

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

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

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

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

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

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

    @pyqtSlot()
    def on_actionNewWindow_triggered(self):
        window = MainWindow()
        window.show()
        window.addressEdit.setText(self.addressEdit.text())
        window.actionStop.setEnabled(True)
        window.on_actionGo_triggered()

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

    @pyqtSlot()
    def on_actionAboutQt_triggered(self):
        QMessageBox.aboutQt(self, "About Qt")

    def search(self):
        global count
        global flag
        global start
        # print (count)
        self.text_box.hide()
        self.text_box.clear()
        if(flag == 0):
            self.addressEdit.setText(instruction[0])
            self.actionGo.trigger()
            flag = 1
        else:
            if(count > 18):
                MainWindow._window_list.remove(self)
                exit()
            elif(count == 18):
                self.addressEdit.setText("file:///E:/courses/sem7/ell890(CN)/STIMULUS/end.html")
                self.actionGo.trigger()
            elif (count%3==0):
                self.addressEdit.setText("file:///E:/courses/sem7/ell890(CN)/STIMULUS/"+search_instruction[int(count/3)]+".html")
                self.actionGo.trigger()
            elif(count%3==1):
                print (int(count/3))
                print ("website Loading.....")
                end = time.time()
                print (end - start)
                self.addressEdit.setText(urls[int(count/3)])
                self.actionGo.trigger()
                end = time.time()
                self.text_box.show()
                self.text_box.insertPlainText(msg[int(count/3)])
            else:
                print ("website navigation completed")
                end = time.time()
                print (end - start)
                self.addressEdit.setText("file:///E:/courses/sem7/ell890(CN)/STIMULUS/fixation.html")
                self.actionGo.trigger()
                # time.sleep(15)
                # self.search()
            count = count + 1
class InputTab(SerafinInputTab):
    def __init__(self, parent):
        super().__init__(parent)
        self.ref_data = None
        self.test_data = None
        self.ref_mesh = None

        self.polygons = []
        self.selected_polygon = None
        self.ref_mesh = None
        self.polygon_added = False   # is the intersection between the mesh and the selected polygon calculated?

        # initialize the map for locating polygons
        canvas = PolygonMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False

        self._initWidgets()
        self._setLayout()
        self._bindEvents()

    def _initWidgets(self):
        # create the button open the reference file
        self.btnOpen.setText('Load\nReference')

        # create the button open the test file
        self.btnOpenTest = QPushButton('Load\nTest', self, icon=self.style().standardIcon(QStyle.SP_DialogOpenButton))
        self.btnOpenTest.setToolTip('<b>Open</b> a Serafin file')
        self.btnOpenTest.setFixedSize(105, 50)
        self.btnOpenTest.setEnabled(False)

        # create the button open the polygon file
        self.btnOpenPolygon = QPushButton('Load polygons\n(optional)', self,
                                          icon=self.style().standardIcon(QStyle.SP_DialogOpenButton))
        self.btnOpenPolygon.setToolTip('<b>Open</b> a .i2s or .shp file')
        self.btnOpenPolygon.setFixedSize(135, 50)
        self.btnOpenPolygon.setEnabled(False)

        # create the button for locating polygons on map
        self.locatePolygons = QPushButton('Locate polygons\non map',
                                          icon=self.style().standardIcon(QStyle.SP_DialogHelpButton))
        self.locatePolygons.setToolTip('<b>Open</b> a map with polygons')
        self.locatePolygons.setFixedSize(135, 50)
        self.locatePolygons.setEnabled(False)

        # create some text fields displaying the IO files info
        self.testNameBox = QLineEdit()
        self.testNameBox.setReadOnly(True)
        self.testNameBox.setFixedHeight(30)
        self.testNameBox.setMinimumWidth(600)
        self.testSummaryTextBox = QPlainTextEdit()
        self.testSummaryTextBox.setReadOnly(True)
        self.testSummaryTextBox.setMinimumHeight(40)
        self.testSummaryTextBox.setMaximumHeight(50)
        self.testSummaryTextBox.setMinimumWidth(600)
        self.polygonNameBox = QPlainTextEdit()
        self.polygonNameBox.setReadOnly(True)
        self.polygonNameBox.setFixedHeight(50)
        self.polygonNameBox.setMinimumWidth(600)

        # create combo box widgets for choosing the variable
        self.varBox = QComboBox()
        self.varBox.setFixedSize(400, 30)

        # create combo box widgets for choosing the polygon
        self.polygonBox = QComboBox()
        self.polygonBox.setFixedSize(400, 30)

    def _bindEvents(self):
        self.btnOpen.clicked.connect(self.btnOpenRefEvent)
        self.btnOpenTest.clicked.connect(self.btnOpenTestEvent)
        self.btnOpenPolygon.clicked.connect(self.btnOpenPolygonEvent)
        self.locatePolygons.clicked.connect(self.locatePolygonsEvent)
        self.polygonBox.currentTextChanged.connect(self.selectPolygonEvent)
        self.map.closeEvent = lambda event: self.locatePolygons.setEnabled(True)

    def _setLayout(self):
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 20))
        mainLayout.setSpacing(15)

        hlayout = QHBoxLayout()
        hlayout.setAlignment(Qt.AlignLeft)
        hlayout.addItem(QSpacerItem(50, 1))
        hlayout.addWidget(self.btnOpen)
        hlayout.addWidget(self.btnOpenTest)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.langBox)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.btnOpenPolygon)
        hlayout.addWidget(self.locatePolygons)
        hlayout.setSpacing(10)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('     Reference'), 1, 1)
        glayout.addWidget(self.inNameBox, 1, 2)
        glayout.addWidget(QLabel('     Summary'), 2, 1)
        glayout.addWidget(self.summaryTextBox, 2, 2)
        glayout.addWidget(QLabel('     Test'), 3, 1)
        glayout.addWidget(self.testNameBox, 3, 2)
        glayout.addWidget(QLabel('     Summary'), 4, 1)
        glayout.addWidget(self.testSummaryTextBox, 4, 2)
        glayout.addWidget(QLabel('     Polygons'), 5, 1)
        glayout.addWidget(self.polygonNameBox, 5, 2)
        glayout.setAlignment(Qt.AlignLeft)
        glayout.setVerticalSpacing(10)

        mainLayout.addLayout(glayout)
        mainLayout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('     Select the variable to compare'), 1, 1)
        glayout.addWidget(self.varBox, 1, 2)
        glayout.addWidget(QLabel('     Select the comparison domain'), 2, 1)
        glayout.addWidget(self.polygonBox, 2, 2)
        glayout.setSpacing(10)
        mainLayout.addLayout(glayout)
        mainLayout.setAlignment(glayout, Qt.AlignTop | Qt.AlignLeft)

        mainLayout.addItem(QSpacerItem(30, 15))
        mainLayout.addWidget(QLabel('   Message logs'))
        mainLayout.addWidget(self.logTextBox.widget)
        self.setLayout(mainLayout)
        self.setLayout(mainLayout)

    def _reinitRef(self):
        self.reset()
        self.ref_mesh = None
        self.ref_data = None
        self.polygon_added = False
        self.selected_polygon = None
        self.polygons = []

        self.test_data = None
        self.testSummaryTextBox.clear()
        self.testNameBox.clear()
        self.polygonNameBox.clear()
        self.varBox.clear()
        self.polygonBox.clear()
        self.btnOpenTest.setEnabled(False)
        self.btnOpenPolygon.setEnabled(False)
        self.locatePolygons.setEnabled(False)

        self.map.hide()
        self.has_map = False
        self.parent.reset()

    def _reinitTest(self, filename):
        self.test_data = None
        self.testNameBox.setText(filename)
        self.testSummaryTextBox.clear()
        self.varBox.clear()

    def locatePolygonsEvent(self):
        if not self.has_map:
            self.map.canvas.reinitFigure(self.ref_mesh, self.polygons,
                                         ['Polygon %d' % (i+1) for i in range(len(self.polygons))])
            self.has_map = True
        self.locatePolygons.setEnabled(False)
        self.map.show()

    def selectPolygonEvent(self, text):
        if not text:
            return
        elif text == 'Entire mesh':
            self.selected_polygon = None
        else:
            polygon_index = int(text.split()[1]) - 1
            self.selected_polygon = self.polygons[polygon_index]
        self.polygon_added = False

    def btnOpenRefEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitRef()
        success, data = self.read_2d(filename)
        if not success:
            return

        self.ref_data = data

        # record the mesh
        self.parent.inDialog()
        meshLoader = LoadMeshDialog('comparison', self.ref_data.header)
        self.ref_mesh = meshLoader.run()
        self.parent.outDialog()
        if meshLoader.thread.canceled:
            self.summaryTextBox.clear()
            self.ref_data = None
            return

        self.parent.add_reference()

        self.btnOpenTest.setEnabled(True)
        self.btnOpenPolygon.setEnabled(True)
        self.polygonBox.addItem('Entire mesh')

    def btnOpenTestEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitTest(filename)
        success, data = self.read_2d(filename, update=False)
        if not success:
            return

        # check if the mesh is identical to the reference
        if not self.ref_data.header.same_2d_mesh(data.header):
            QMessageBox.critical(self, 'Error', 'The mesh is not identical to the reference.', QMessageBox.Ok)
            return

        # check if the test file has common variables with the reference file
        common_vars = [(var_ID, var_names) for var_ID, var_names
                       in zip(self.ref_data.header.var_IDs, self.ref_data.header.var_names)
                       if var_ID in data.header.var_IDs]
        if not common_vars:
            QMessageBox.critical(self, 'Error', 'No common variable with the reference file.', QMessageBox.Ok)
            return

        self.test_data = data
        self.testNameBox.setText(filename)
        self.testSummaryTextBox.appendPlainText(self.test_data.header.summary())

        self.parent.add_test()

        for var_ID, var_name in common_vars:
            self.varBox.addItem(var_ID + ' (%s)' % var_name.decode(Serafin.SLF_EIT).strip())

    def btnOpenPolygonEvent(self):
        success, filename, polygons = open_polygons()
        if not success:
            return

        self.polygons = polygons
        self.map.close()
        self.map.has_figure = False

        self.polygonNameBox.clear()
        self.polygonNameBox.appendPlainText(filename + '\n' + 'The file contains {} polygon{}.'.format(
            len(self.polygons), 's' if len(self.polygons) > 1 else ''))

        self.polygonBox.clear()
        self.polygonBox.addItem('Entire mesh')
        for i in range(len(self.polygons)):
            self.polygonBox.addItem('Polygon %d' % (i+1))
        self.locatePolygons.setEnabled(True)
Example #17
0
class Assembler(QMainWindow):
    def __init__(self, parent=None):
        super(Assembler, self).__init__(parent)
        self.resize(800, 600)
        self.filename  = None
        self.filetuple = None
        self.dirty = False  # Refers to Data Page only.
        self.nb = None
        centralwidget = QWidget(self)
        gridLayout = QGridLayout(centralwidget)
        self.tabWidget = QTabWidget(centralwidget)


        # textbox

        self.tab = QWidget()
        font = QFont()
        font.setFamily("Inconsolata")
        font.setPointSize(14)
        self.tab.setFont(font)
        gridLayout_3 = QGridLayout(self.tab)
        self.plainTextEdit = QPlainTextEdit(self.tab)
        self.plainTextEdit.installEventFilter(self)
        self.plainTextEdit.setAcceptDrops(True)
        gridLayout_3.addWidget(self.plainTextEdit, 0, 0, 1, 1)
        self.tabWidget.addTab(self.tab, "")





        self.tab_2 = QWidget()
        self.tab_2.setFont(font)
        gridLayout_2 = QGridLayout(self.tab_2)
        self.plainTextEdit_2 = QPlainTextEdit(self.tab_2)
        gridLayout_2.addWidget(self.plainTextEdit_2, 0, 0, 1, 1)
        self.tabWidget.addTab(self.tab_2, "")

        self.tab_3 = QWidget()
        self.tab_3.setFont(font)
        gridLayout_3 = QGridLayout(self.tab_3)
        self.checkbox = QCheckBox("Cloning genes by tailed primers (no pYPKa_A vectors constructed)")
        self.checkbox.setChecked(True)
        gridLayout_3.addWidget(self.checkbox, 0, 0, 0, 0)
        self.tabWidget.addTab(self.tab_3, "")

        gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
        self.setCentralWidget(centralwidget)
        menubar = QMenuBar(self)
        menubar.setGeometry(QRect(0, 0, 800, 29))
        menu_File = QMenu(menubar)
        self.menu_Solve = QMenu(menubar)
        self.menu_Help = QMenu(menubar)
        self.setMenuBar(menubar)
        self.statusbar = QStatusBar(self)
        self.setStatusBar(self.statusbar)
        self.action_New = QAction(self)
        self.actionSave_As = QAction(self)
        self.action_Save = QAction(self)
        self.action_Open = QAction(self)
        self.action_Quit = QAction(self)
        self.action_About = QAction(self)
        self.actionShow_CCPL = QAction(self)
        self.action_Solve  = QAction(self)
        self.action_OpenNB = QAction(self)
        self.action_CCPL = QAction(self)
        self.action_Help = QAction(self)
        menu_File.addAction(self.action_New)
        menu_File.addAction(self.action_Open)
        menu_File.addAction(self.actionSave_As)
        menu_File.addAction(self.action_Save)
        menu_File.addSeparator()
        menu_File.addAction(self.action_Quit)
        self.menu_Solve.addAction(self.action_Solve)
        self.menu_Solve.addAction(self.action_OpenNB)
        self.menu_Help.addAction(self.action_About)
        #self.menu_Help.addAction(self.action_CCPL)
        #self.menu_Help.addAction(self.action_Help)
        menubar.addAction(menu_File.menuAction())
        menubar.addAction(self.menu_Solve.menuAction())
        menubar.addAction(self.menu_Help.menuAction())

        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab),\
                                   "Data Page")
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2),\
                                   "Assembly log")
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3),\
                                   "Settings")
        menu_File.setTitle("&File")
        self.menu_Solve.setTitle("&Assemble")
        self.menu_Help.setTitle("&About")
        self.tabWidget.setCurrentIndex(0)
        self.action_New.setText("&New")
        self.action_Open.setText("&Open")
        self.actionSave_As.setText("Save &As")
        self.action_Save.setText("&Save")
        self.action_Quit.setText("&Quit")
        self.action_Solve.setText("&Assemble")
        self.action_OpenNB.setText("&Open &pathway")
        self.action_About.setText("&About")
        #self.action_CCPL.setText("&CCPL")
        #self.action_Help.setText("&Help")
        self.action_Quit.triggered.connect(self.close)
        allToolBar = self.addToolBar("AllToolBar")
        allToolBar.setObjectName("AllToolBar")
        self.addActions(allToolBar, (self.action_Open,
                                     self.actionSave_As,
                                     self.action_Save,
                                     self.action_Solve,
                                     self.action_OpenNB,
                                     self.action_Quit ))
        self.action_New.triggered.connect(self.fileNew)
        self.action_Open.triggered.connect(self.fileOpen)
        self.actionSave_As.triggered.connect(self.fileSaveAs)
        self.action_Save.triggered.connect(self.fileSave)
        self.action_Solve.triggered.connect(self.solveAssembly)
        self.action_OpenNB.triggered.connect(self.openNB)
        self.action_About.triggered.connect(self.aboutBox)
        #self.action_CCPL.triggered.connect(self.displayCCPL)
        #self.action_Help.triggered.connect(self.help)
        self.plainTextEdit.textChanged.connect(self.setDirty)
        self.action_New = self.editAction(self.action_New, None,\
                            'ctrl+N', 'filenew', 'New File.')
        self.action_Open = self.editAction(self.action_Open, None,
                            'ctrl+O', 'fileopen', 'Open File.')
        self.actionSave_As = self.editAction(self.actionSave_As,\
                            None, 'ctrl+A', 'filesaveas',\
                            'Save and Name File.')
        self.action_Save = self.editAction(self.action_Save, None,
                            'ctrl+S', 'filesave', 'Save File.')
        self.action_Solve = self.editAction(self.action_Solve, None,
                            '', 'solve', 'Assemble.')
        self.action_OpenNB = self.editAction(self.action_OpenNB, None,
                            '', 'ipynb', 'Open pathway.')
        self.action_About = self.editAction(self.action_About, None,
                            'ctrl+B', 'about','Pop About Box.')
        self.action_CCPL = self.editAction(self.action_CCPL, None,
                            'ctrl+G', 'licence', 'Show Licence')
        self.action_Help = self.editAction(self.action_Help, None,
                            'ctrl+H', 'help', 'Show Help Page.')
        self.action_Quit =  self.editAction(self.action_Quit, None,
                            'ctrl+Q', 'quit', 'Quit the program.')
        self.plainTextEdit_2.setReadOnly(True)

        self.setWindowTitle("ypkpathway")
        self.setWindowIcon(QIcon( resource_filename("ypkpathway","icons/ypkpathway.png")))
        self.plainTextEdit.setFocus()

    def eventFilter(self, object, event):
        #print(event.type(), QEvent.DragEnter, object, self.plainTextEdit)
        if (object is self.plainTextEdit):
            if (event.type() == QEvent.DragEnter):
                if event.mimeData().hasUrls():
                    event.accept()   # must accept the dragEnterEvent or else the dropEvent can't occur !!!
                    print("accept")
                else:
                    event.ignore()
                    print("ignore")
            if (event.type() == QEvent.Drop):
                if event.mimeData().hasUrls():   # if file or link is dropped
                    urlcount = len(event.mimeData().urls())  # count number of drops
                    url = event.mimeData().urls()[0]   # get first url
                    object.setPlainText('abc')   # assign first url to editline
                    event.accept()  # doesnt appear to be needed
                    print(456)
                    return True
            return False # lets the event continue to the edit
        return False

    def setDirty(self):
        '''On change of text in textEdit window, set the flag
        "dirty" to True'''
        index = self.tabWidget.currentIndex()
        if index is not 0:
            return
        if self.dirty:
            return True
        self.dirty = True
        self.updateStatus('self.dirty set to True')

    def clearDirty(self):
        'Clear dirty flag'
        self.dirty = False

    def fileNew(self):
        '''Clear both Data Page and Solution Page.'''
        self.plainTextEdit.setPlainText(' ')
        self.plainTextEdit_2.setPlainText(' ')
        self.clearDirty()
        self.filename = None

    def okToContinue(self):
        if self.dirty:
            reply = QMessageBox.question(self,
                    "Data Loader - Unsaved Changes",
                    "Save unsaved changes?",
                    QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                self.clearDirty()
                return self.fileSave()
        return True

    def okRead(self):
        'Pop-up a warning message.'
        reply = QMessageBox.warning(self,
                "Warning",
                '''\nFile Open and Save only in Data Page
\n\(Use SaveAs for the Assembly log)''', QMessageBox.Ok)
        return True

    def fileOpen(self):
        '''Open a file in Data Page (with index == 0)'''
        if self.tabWidget.currentIndex():
            self.okRead()
            return
        if not self.okToContinue():
            return
        dir_ = (os.path.dirname(str(self.filename)) if self.filename is not None else ".")
        filetuple = QFileDialog.getOpenFileName(self,"Open File", dir_,)
        self.filename = filetuple[0]
        #  QFileDialog returns a tuple x with x[0] = file name and
        #  x[1] = type of filter.
        if self.filename:
            self.loadFile(self.filename)
            self.updateStatus('New file opened.')

    def loadFile(self, fname=None):
        fl = open(fname, "r")
        text = fl.read()
        self.plainTextEdit.setPlainText(text)
        self.dirty = False

    def fileSave(self):
        '''Save file with current file name.'''
        if self.tabWidget.currentIndex():
            self.okRead()
            return
        if self.filename is None:
            return self.fileSaveAs()
        else:
            flname = self.filename
            if flname:
                tempText = self.plainTextEdit.toPlainText()
                with open(flname, 'w') as fl: fl.write(tempText)
                self.dirty = False
                self.updateStatus('File saved.')
                return True
            else:
                self.updateStatus('Failed to save... ')
                return False
        self.filename = None
        self.dirty = False

    def fileSaveAs(self):
        '''Save file with a new name.'''
        qpr = self.qprintline
        fname = self.filename or "NoName.txt"
        self.filename = str(QFileDialog.getSaveFileName(self,"ypkpathway - Save File", fname))
        flname = self.filename or "NoName.txt"
        self.filename = flname
        fl = open(flname, 'w')
        tempText = str(self.plainTextEdit.toPlainText())
        fl.write(tempText)
        fl.close()
        self.dirty = False
        self.updateStatus('File saved.')


    def solveAssembly(self):
        printline = self.qprintline
        self.plainTextEdit_2.clear()
        self.tabWidget.setCurrentIndex(1)
        flbase = os.path.basename(str(self.filename))

        title = 'Assembly log for ' + flbase

        printline('='*len(title))
        printline(title)
        printline('='*len(title))


        #print(type(self.plainTextEdit.toPlainText()))
        #qstringobj = self.plainTextEdit.toPlainText().encode('utf-8')
        #print(type(qstringobj)) #<class 'PyQt4.QtCore.QString'>
        #print(qstringobj.toUtf8()[3268:3279])
        #print(str(qstringobj.toUtf8()[3268:3279]))
        #print(type(rawtext), "rawtext")
        #codec0 = .QTextCodec.codecForName("UTF-16");
        #rawtext = unicode(codec0.fromUnicode(tmp), 'UTF-16')
        #unicode(qstringobj.toUtf8(), encoding="UTF-8").decode()
        
        qstringobj = self.plainTextEdit.toPlainText()

        #import sys;sys.exit(42)

        pth = parse( qstringobj )
        
        #import sys;sys.exit(42)

        if len(pth)==0:
            printline("No of sequences found in Data window")
            return

        if self.filename is None:
            self.fileSaveAs()

        dir_, ext = os.path.splitext( str(self.filename))

        fl, log = ypkpathway.pathway( pth, dir_, pYPKa_A = not self.checkbox.isChecked(), print = printline)

        if not fl:
            return

        with open(os.path.join(dir_, "log.txt"),"w") as f: f.write(log)

        shutil.copy2( str(self.filename), os.path.join(dir_, "INDATA_"+os.path.basename(str(self.filename))))

        printline('')
        printline('\n\nAssembly finished.')
        printline('click on the Open pathway button above to open the pathway in the default web browser')
        self.nb =  fl.path

    def qprintline(self, line):
        '''Append one line to Solution Page.'''
        self.plainTextEdit_2.appendPlainText(line.rstrip()) #.decode("utf8"))
        QApplication.processEvents()

    def openNB(self):
        if self.nb:
            subprocess.Popen(["ipython", "notebook", self.nb])



    def aboutBox(self):

        from PyQt5.QtCore import QT_VERSION_STR
        from PyQt5.Qt import PYQT_VERSION_STR
        from sip import SIP_VERSION_STR
        from ._version import get_versions
        __version__ = get_versions()["version"][:5]
        del get_versions
        from IPython import __version__ as IPython_version

        QMessageBox.about(self, "About ypkpathway",
                             """<b>Planning of yeast pathway kit constructions.</b>
                                <p>version: {}<br>
                                 Copyright 2015-2017 Björn Johansson.
                                 This software is released under a BSD style license.
                                 This software comes with no warranties
                                 expressed or implied.<br><br>
                                 Python version: {}<br><br>
                                 IPython version: {}<br>
                                 Qt version: {}<br>
                                 SIP version: {}<br>
                                 PyQt version: {}<br>
                                 pydna version: {}<br></p>
                                 """.format(__version__,
                                            sys.version,
                                            IPython_version,
                                            QT_VERSION_STR,
                                            SIP_VERSION_STR,
                                            PYQT_VERSION_STR,
                                            pydna.__version__[:5]))




    def displayCCPL(self):
        '''Read and display CCPL licence.'''
        self.plainTextEdit.setPlainText(open('CCPL.txt').read())
        self.dirty = False
        self.filename = 'COPYING.txt'
        self.updateStatus('CCPL displayed.')

    def help(self):
        '''Read and display a help file- currently the README.txt.'''
        self.plainTextEdit.setPlainText(open('README.md').read())
        self.dirty = False
        self.filename = 'README.txt'
        self.updateStatus('README displayed.')

    def addActions(self, target, actions):
        '''Actions are added to Tool Bar.'''
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def editAction(self, action, slot=None, shortcut=None, icon=None,
                     tip=None):
        '''This method adds to action: icon, shortcut, ToolTip,\
        StatusTip and can connect triggered action to slot '''
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % (icon)))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            action.triggered.connect(slot)
        return action

    def qreadline(self, lineNo):
        '''Read one line from Data Page (lineNo starts with 0)'''
        return str(self.plainTextEdit.document().\
            findBlockByLineNumber(lineNo).text()).rstrip()

    def updateStatus(self, message):
        '''Keep status current.'''
        if self.filename is not None:
            flbase = os.path.basename(str(self.filename))
            self.setWindowTitle(str("ypkpathway - " +\
                                         flbase + "[*]") )
            self.statusBar().showMessage(message, 5000)
            self.setWindowModified(self.dirty)
Example #18
0
class SendTab(QWidget):
    TITLE = "Send"
    HOVER = "Use your seed to cosign a transaction."

    # FIXME (add support and UX for this)
    UNITS = "sats"

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

        vbox = QVBoxLayout(self)

        self.psbtLabel = QLabel(
            "<b>Partially Signed Bitcoin Transaction</b> (required)")
        self.psbtLabel.setToolTip(
            "What your online computer is asking you to sign, in base64 format."
        )
        self.psbtEdit = QPlainTextEdit("")
        self.psbtEdit.setPlaceholderText(
            "Something like this:\n\ncHNidP8BAH0CAAAAA...")

        # Network toggle
        # https://www.tutorialspoint.com/pyqt/pyqt_qradiobutton_widget.htm
        self.network_label = QLabel("<b>Bitcoin Network</b>")
        self.network_label.setToolTip(BITCOIN_NETWORK_TOOLTIP)

        hbox = QHBoxLayout(self)

        self.infernetwork_button = QRadioButton("Automatic")
        self.infernetwork_button.setToolTip(
            "Non-experts should choose this option."
            "<br/><br/>"
            "The current PSBT serialization format does not encode which network the transaction is on, but this software can usually infer the network based on the BIP32 path used. "
            "If the address displayed is in the wrong format (<i>bc1...</i> vs <i>tb1...</i>) then you may need to manually select the network."
        )
        self.infernetwork_button.setChecked(True)

        self.mainnet_button = QRadioButton("Mainnet")
        self.mainnet_button.setToolTip(BITCOIN_MAINNET_TOOLTIP)
        self.mainnet_button.setChecked(False)

        self.testnet_button = QRadioButton("Testnet")
        self.testnet_button.setToolTip(BITCOIN_TESTNET_TOOLTIP)
        self.testnet_button.setChecked(False)

        for widget in (
                self.infernetwork_button,
                self.mainnet_button,
                self.testnet_button,
        ):
            hbox.addWidget(widget)
        hbox.setAlignment(Qt.AlignCenter)

        self.psbtSubmitButton = QPushButton("Decode Transaction")
        self.psbtSubmitButton.clicked.connect(self.decode_psbt)

        self.fullSeedLabel = QLabel("<b>Full 24-Word Seed Phrase</b>")
        self.fullSeedLabel.setToolTip(
            "Needed to sign the PSBT. You can first decode the transaction and inspect it without supplying your seed phrase."
        )
        self.fullSeedEdit = QPlainTextEdit("")
        self.fullSeedEdit.setPlaceholderText(
            "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo"
        )

        self.fullSeedSubmitButton = QPushButton("Sign Transaction")
        self.fullSeedSubmitButton.clicked.connect(self.sign_psbt)

        self.psbtDecodedLabel = QLabel("")
        self.psbtDecodedLabel.setToolTip(
            "The summary of what this transaction does. Multiwallet statelessly verifies all inputs belong to the same quorum and that any change is properly returned."
        )

        self.psbtDecodedROEdit = QPlainTextEdit("")
        self.psbtDecodedROEdit.setReadOnly(True)
        self.psbtDecodedROEdit.setHidden(True)

        self.psbtSignedLabel = QLabel("")
        self.psbtSignedLabel.setToolTip(
            "Signed version for your online computer, which will aggregate signatures and then broadcast to the bitcoin network (once it has the required <i>m-of-n</i> signatures)."
        )
        self.psbtSignedROEdit = QPlainTextEdit("")
        self.psbtSignedROEdit.setReadOnly(True)
        self.psbtSignedROEdit.setHidden(True)

        self.qrButton = QPushButton()
        self.qrButton.setText("QR")
        self.qrButton.setToolTip(
            "For transmitting to your online computer via webcam."
            "<br/><br/>"
            "This is a great way to preserve your airgap.")
        self.qrButton.setHidden(True)
        self.qrButton.clicked.connect(self.make_qr_popup)

        for widget in (
                self.psbtLabel,
                self.psbtEdit,
                self.network_label,
        ):
            vbox.addWidget(widget)

        vbox.addLayout(hbox)

        for widget in (
                self.psbtSubmitButton,
                self.fullSeedLabel,
                self.fullSeedEdit,
                self.fullSeedSubmitButton,
                self.psbtDecodedLabel,
                self.psbtDecodedROEdit,
                self.psbtSignedLabel,
                self.psbtSignedROEdit,
                self.qrButton,
        ):
            vbox.addWidget(widget)

        self.setLayout(vbox)

    def decode_psbt(self):
        return self.process_psbt(sign_tx=False)

    def sign_psbt(self):
        return self.process_psbt(sign_tx=True)

    def make_qr_popup(self):
        return qr_dialog(
            qwidget=self,
            qr_text=self.psbtSignedROEdit.toPlainText(),
            window_title=self.psbtSignedLabel.text(),
        )

    def process_psbt(self, sign_tx=True):
        # Clear any previous submission in case of errors
        self.psbtDecodedLabel.setText("")
        self.psbtDecodedROEdit.clear()
        self.psbtDecodedROEdit.setHidden(True)

        self.psbtSignedLabel.setText("")
        self.psbtSignedROEdit.clear()
        self.psbtSignedROEdit.setHidden(True)

        self.qrButton.setHidden(True)
        self.qrButton.setText("")
        # TODO: why setText and not hide?

        if self.infernetwork_button.isChecked():
            PARSE_WITH_TESTNET = None
        elif self.mainnet_button.isChecked():
            PARSE_WITH_TESTNET = False
        elif self.testnet_button.isChecked():
            PARSE_WITH_TESTNET = True
        else:
            # This shouldn't be possible
            raise Exception(
                "Invalid Network Selection: No Radio Button Chosen")

        psbt_str = _clean_submisission(self.psbtEdit.toPlainText())

        if not psbt_str:
            return _msgbox_err(
                main_text="No PSBT Supplied",
                informative_text="Enter a PSBT to decode and/or sign.",
            )

        try:
            psbt_obj = PSBT.parse_base64(b64=psbt_str,
                                         testnet=PARSE_WITH_TESTNET)
        except Exception as e:
            if type(e) is ValueError and str(e) == "Mainnet/Testnet mixing":
                # TODO: less hackey way to catch this error?
                return _msgbox_err(
                    main_text="PSBT Network Error",
                    informative_text=
                    "The network you selected doesn't match the PSBT.",
                    detailed_text=str(e),
                )
            else:
                return _msgbox_err(
                    main_text="PSBT Parse Error",
                    informative_text="Are you sure that's a valid PSBT?",
                    detailed_text=str(e),
                )

        # Parse TX
        self.TX_FEE_SATS = psbt_obj.tx_obj.fee()
        self.IS_TESTNET = psbt_obj.tx_obj.testnet

        # Validate multisig transaction
        # TODO: abstract some of this into buidl library?
        # Below is confusing because we perform both validation and coordinate signing.

        # This tool only supports a TX with the following constraints:
        #   We sign ALL inputs and they have the same multisig wallet (quorum + pubkeys)
        #   There can only be 1 output (sweep transaction) or 2 outputs (spend + change).
        #   If there is change, we validate it has the same multisig wallet as the inputs we sign.

        # Gather TX info and validate
        inputs_desc = []
        for cnt, psbt_in in enumerate(psbt_obj.psbt_ins):
            psbt_in.validate()  # redundant but explicit

            if type(psbt_in.witness_script) != WitnessScript:
                return _msgbox_err(
                    main_text="Input #{cnt} does not contain a witness script",
                    informative_text=
                    "This tool can only sign p2wsh transactions.",
                )

            # Determine quroum_m (and that it hasn't changed between inputs)
            try:
                quorum_m = OP_CODE_NAMES[
                    psbt_in.witness_script.commands[0]].split("OP_")[1]
            except Exception:
                return _msgbox_err(
                    main_text="Non-p2wsh Input",
                    informative_text=
                    f"Witness script for input #{cnt} is not p2wsh",
                    detailed_text=f"PSBT Input:\n {psbt_in}",
                )

            # for calculating msig fingerprint
            root_xfp_hexes = []
            for _, details in psbt_in.named_pubs.items():
                root_xfp_hexes.append(details.root_fingerprint.hex())

            input_desc = {
                "quorum":
                f"{quorum_m}-of-{len(root_xfp_hexes)}",
                "root_xfp_hexes":
                root_xfp_hexes,
                "prev_txhash":
                psbt_in.tx_in.prev_tx.hex(),
                "prev_idx":
                psbt_in.tx_in.prev_index,
                "n_sequence":
                psbt_in.tx_in.sequence,
                "sats":
                psbt_in.tx_in.value(),
                # TODO: would be possible for transaction to be p2sh-wrapped p2wsh (can we tell?)
                "addr":
                psbt_in.witness_script.address(testnet=self.IS_TESTNET),
                # "p2sh_addr": psbt_in.witness_script.p2sh_address(testnet=self.IS_TESTNET),
                "witness_script":
                str(psbt_in.witness_script),
                "msig_digest":
                _calculate_msig_digest(quorum_m=quorum_m,
                                       root_xfp_hexes=root_xfp_hexes),
            }
            inputs_desc.append(input_desc)

        if not all(x["msig_digest"] == inputs_desc[0]["msig_digest"]
                   for x in inputs_desc):
            return _msgbox_err(
                main_text="Inputs Contain Conflicting Wallet Quorums",
                informative_text=
                "This transaction is not inherently bad, but transactions of this type are only possible for experts. Please construct 1 or more transactions with one input instead.",
                detailed_text=f"For developers: {inputs_desc}",
            )

        TOTAL_INPUT_SATS = sum([x["sats"] for x in inputs_desc])

        # This too only supports TXs with 1-2 outputs (sweep TX OR spend+change TX):
        if len(psbt_obj.psbt_outs) > 2:
            return _msgbox_err(
                main_text="Too Many Outputs",
                informative_text=
                f"Multiwallet does not support batching, and your transaction has {len(psbt_obj.psbt_outs)} outputs.",
                detailed_text=
                "Please construct a transaction with <= 2 outputs.",
            )

        spend_addr, output_spend_sats = "", 0
        outputs_desc = []
        for cnt, psbt_out in enumerate(psbt_obj.psbt_outs):
            psbt_out.validate()  # redundant but explicit

            output_desc = {
                "sats":
                psbt_out.tx_out.amount,
                "addr_type":
                psbt_out.tx_out.script_pubkey.__class__.__name__.rstrip(
                    "ScriptPubKey"),
            }

            if psbt_out.witness_script:
                output_desc["addr"] = psbt_out.witness_script.address(
                    testnet=self.IS_TESTNET)
            else:
                output_desc["addr"] = psbt_out.tx_out.script_pubkey.address(
                    testnet=self.IS_TESTNET)

            if psbt_out.named_pubs:
                # Validate below that this is correct and abort otherwise
                output_desc["is_change"] = True

                root_xfp_hexes = []  # for calculating msig fingerprint
                for _, details in psbt_out.named_pubs.items():
                    root_xfp_hexes.append(details.root_fingerprint.hex())

                # Determine quroum_m (and that it hasn't changed between inputs)
                try:
                    quorum_m = OP_CODE_NAMES[
                        psbt_out.witness_script.commands[0]].split("OP_")[1]
                except Exception:
                    return _msgbox_err(
                        main_text="Non-p2wsh Change Output",
                        informative_text=
                        "This transaction may be trying to trick you into sending change to a third party.",
                        detailed_text=
                        f"Witness script for output #{cnt} is not p2wsh: {psbt_out}",
                    )

                output_msig_digest = _calculate_msig_digest(
                    quorum_m=quorum_m, root_xfp_hexes=root_xfp_hexes)
                if output_msig_digest != inputs_desc[0]["msig_digest"]:
                    return _msgbox_err(
                        main_text="Invalid Change Detected",
                        informative_text=
                        f"Output #{cnt} is claiming to be change but has different multisig wallet(s)! Do a sweep transaction (1-output) if you want this wallet to cosign.",
                        detailed_text=f"For developers: {outputs_desc}",
                    )
            else:
                output_desc["is_change"] = False
                spend_addr = output_desc["addr"]
                output_spend_sats = output_desc["sats"]

            outputs_desc.append(output_desc)

        # Sanity check
        if len(outputs_desc) != len(psbt_obj.psbt_outs):
            return _msgbox_err(
                main_text="PSBT Parse Error",
                informative_text=
                f"{len(outputs_desc)} outputs in TX summary doesn't match {len(psbt_obj.psbt_outs)} outputs in PSBT.",
            )

        # Confirm if 2 outputs we only have 1 change and 1 spend (can't be 2 changes or 2 spends)
        if len(outputs_desc) == 2:
            if all(x["is_change"] == outputs_desc[0]["is_change"]
                   for x in outputs_desc):
                return _msgbox_err(
                    main_text="Change-Only Transaction with 2 Outputs",
                    informative_text=
                    "Transactions with 2 outputs that are BOTH change are not allowed, as only experts can properly validate them. Please construct a transaction with fewer outputs.",
                    detailed_text=f"For developers: {outputs_desc}",
                )

        TX_SUMMARY = " ".join([
            inputs_desc[0]["quorum"],
            "PSBT sends",
            _format_satoshis(output_spend_sats, in_btc=self.UNITS == "btc"),
            "to",
            spend_addr,
            "with a fee of",
            _format_satoshis(self.TX_FEE_SATS, in_btc=self.UNITS == "btc"),
            f"({round(self.TX_FEE_SATS / TOTAL_INPUT_SATS * 100, 2)}% of spend)",
        ])
        self.psbtDecodedLabel.setText(
            f"<b>Decoded Transaction Summary</b> - {'Testnet' if self.IS_TESTNET else 'Mainnet'}"
        )
        self.psbtDecodedROEdit.setHidden(False)
        self.psbtDecodedROEdit.appendPlainText(TX_SUMMARY)

        # TODO: surface this to user somehow
        to_print = []
        to_print.append("DETAILED VIEW")
        to_print.append(f"TXID: {psbt_obj.tx_obj.id()}")
        to_print.append(
            f"Network: {'Testnet' if psbt_obj.tx_obj.testnet else 'Mainnet'}")
        to_print.append("-" * 80)
        to_print.append(f"{len(inputs_desc)} Input(s):")
        for cnt, input_desc in enumerate(inputs_desc):
            to_print.append(f"  input #{cnt}")
            for k in input_desc:
                to_print.append(f"    {k}: {input_desc[k]}")
        to_print.append("-" * 80)
        to_print.append(f"{len(outputs_desc)} Output(s):")
        for cnt, output_desc in enumerate(outputs_desc):
            to_print.append(f"  output #{cnt}")
            for k in output_desc:
                to_print.append(f"    {k}: {output_desc[k]}")
        print("\n".join(to_print))

        seed_phrase = _clean_submisission(self.fullSeedEdit.toPlainText())

        if not sign_tx:
            return

        if not seed_phrase:
            return _msgbox_err(
                main_text="No Seed Phrase Supplied",
                informative_text="Cannot sign transaction without seed phrase",
            )

        seed_phrase_num = len(seed_phrase.split())
        if seed_phrase_num not in (12, 15, 18, 21, 24):
            return _msgbox_err(
                main_text="Enter 24 word seed-phrase",
                informative_text=f"You entered {seed_phrase_num} words",
            )

        try:
            hd_priv = HDPrivateKey.from_mnemonic(seed_phrase,
                                                 testnet=self.IS_TESTNET)
        except Exception as e:
            return _msgbox_err(
                main_text="Invalid BIP39 Seed Phrase",
                informative_text="Transaction NOT signed",
                detailed_text=str(e),
            )

        # Derive list of child private keys we'll use to sign the TX
        root_paths = set()
        for cnt, psbt_in in enumerate(psbt_obj.psbt_ins):
            # Redundant safety check:
            bad_txhash = inputs_desc[cnt][
                "prev_txhash"] != psbt_in.tx_in.prev_tx.hex()
            bad_idx = inputs_desc[cnt]["prev_idx"] != psbt_in.tx_in.prev_index
            if bad_txhash or bad_idx:
                return _msgbox_err(
                    main_text="PSBT Parse Error",
                    informative_text="Transaction NOT signed",
                    detailed_text=
                    f"For developers: Input #{cnt} prev_txhash or prev_idx mismatch: \n{PSBT.serialize_base64()}",
                )

            for _, details in psbt_in.named_pubs.items():
                if details.root_fingerprint.hex() == hd_priv.fingerprint().hex(
                ):
                    root_paths.add(details.root_path)

        if not root_paths:
            return _msgbox_err(
                main_text="Wrong Seed",
                informative_text=
                "Seed supplied does not correspond to transaction input(s). Does it belong to another wallet?",
            )

        private_keys = [
            hd_priv.traverse(root_path).private_key for root_path in root_paths
        ]

        try:
            if psbt_obj.sign_with_private_keys(private_keys) is True:
                self.psbtSignedLabel.setText("<b>Signed PSBT to Broadcast</b>")
                self.psbtSignedROEdit.setHidden(False)
                self.psbtSignedROEdit.appendPlainText(
                    psbt_obj.serialize_base64())

                self.qrButton.setHidden(False)
                self.qrButton.setText("QR")
                self.qrButton.setIcon(create_qr_icon())
            else:
                return _msgbox_err(
                    main_text="Transaction Not Signed",
                    informative_text="Couldn't find private key to sign with",
                    detailed_text=
                    "This should've been checked earlier and should not be possible!",
                )
        except Exception as e:
            return _msgbox_err(
                main_text="Transaction Not Signed",
                informative_text="There was an error during signing.",
                detailed_text=f"For developers: {e}",
            )
class ErrorDistributionTab(QWidget):
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab
        self.ewsd = None
        self.xlim = None
        self.ylim = None

        # set up a custom plot viewer
        self.plotViewer = PlotViewer()
        self.plotViewer.exitAct.setEnabled(False)
        self.plotViewer.menuBar.setVisible(False)
        self.XLimitsAct = QAction('Change X limits', self, triggered=self.changeXlimits, enabled=False,
                                  icon=self.style().standardIcon(QStyle.SP_DialogNoButton))
        self.YLimitsAct = QAction('Change Y limits', self, triggered=self.changeYlimits, enabled=False,
                                  icon=self.style().standardIcon(QStyle.SP_DialogNoButton))

        self.plotViewer.toolBar.addAction(self.XLimitsAct)
        self.plotViewer.toolBar.addAction(self.YLimitsAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.xLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.yLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.titleAct)

        # put it in a group box to get a nice border
        gb = QGroupBox()
        ly = QHBoxLayout()
        ly.addWidget(self.plotViewer)
        gb.setLayout(ly)
        gb.setStyleSheet('QGroupBox {border: 8px solid rgb(108, 122, 137); border-radius: 6px }')
        gb.setMinimumWidth(600)

        # create the reference time selection widget
        self.timeSelection = DoubleTimeSelection()

        # create the compute button
        self.btnCompute = QPushButton('Compute', icon=self.style().standardIcon(QStyle.SP_DialogApplyButton))
        self.btnCompute.setFixedSize(105, 50)
        self.btnCompute.clicked.connect(self.btnComputeEvent)

        # create the color map button
        self.btnColorMap = QPushButton('2D View', icon=self.style().standardIcon(QStyle.SP_DialogHelpButton))
        self.btnColorMap.setFixedSize(105, 50)
        self.btnColorMap.clicked.connect(self.btnColorMapEvent)
        self.btnColorMap.setEnabled(False)

        # initialize the map for 2D view
        canvas = ColorMapCanvas()
        self.map = MapViewer(canvas)
        self.has_map = False
        self.map.closeEvent = lambda event: self.btnColorMap.setEnabled(True)

        # create the stats box
        self.resultBox = QPlainTextEdit()
        self.resultBox.setMinimumWidth(400)
        self.resultBox.setMaximumWidth(600)

        # set layout
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.addWidget(self.timeSelection)
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.btnColorMap)
        hlayout.addWidget(self.btnCompute)
        hlayout.setSpacing(10)
        vlayout.addLayout(hlayout)
        vlayout.setAlignment(hlayout, Qt.AlignTop | Qt.AlignRight)
        vlayout.addItem(QSpacerItem(10, 10))
        vlayout.addWidget(self.resultBox)
        vlayout.setAlignment(Qt.AlignHCenter)
        hlayout = QHBoxLayout()
        hlayout.addLayout(vlayout)
        hlayout.addWidget(gb, Qt.AlignHCenter)
        hlayout.setSpacing(10)
        mainLayout.addLayout(hlayout)
        self.setLayout(mainLayout)

        # template for text output
        self.template = '=== EWSD distribution between Ref (frame {}) and Test (frame {}) ===\n'\
                        'Mean         \t{:<30}\n' \
                        'Variance     \t{:<30}\n' \
                        'Min          \t{:<30}\n' \
                        'Quartile 25  \t{:<30}\n' \
                        'Median       \t{:<30}\n' \
                        'Quartile 75  \t{:<30}\n' \
                        'Max          \t{:<30}\n'

    def add_reference(self):
        self.timeSelection.initRef(self.input.ref_data.header.nb_frames)

    def add_test(self):
        self.timeSelection.initTest(self.input.test_data.header.nb_frames)

    def reset(self):
        self.ewsd = None
        self.xlim = None
        self.ylim = None
        self.has_map = False
        self.timeSelection.clearText()
        self.resultBox.clear()
        self.plotViewer.defaultPlot()
        self.plotViewer.current_title = 'Distribution of EWSD (element-wise signed deviation)'
        self.plotViewer.current_ylabel = 'Frequency'
        self.plotViewer.current_xlabel = 'EWSD'
        self.XLimitsAct.setEnabled(False)
        self.YLimitsAct.setEnabled(False)
        self.btnColorMap.setEnabled(False)

    def changeXlimits(self):
        value, ok = QInputDialog.getText(self, 'Change X limits',
                                         'Enter the new X limits',
                                         text=', '.join(map(lambda x: '{:+f}'.format(x),
                                                            self.plotViewer.canvas.axes.get_xlim())))
        if not ok:
            return
        try:
            xmin, xmax = map(float, value.split(','))
        except ValueError:
            QMessageBox.critical(self, 'Error', 'Invalid input.', QMessageBox.Ok)
            return

        self.xlim = xmin, xmax
        self.updateHistogram()
        self.has_map = False

    def changeYlimits(self):
        value, ok = QInputDialog.getText(self, 'Change Y limits',
                                         'Enter the new Y limits',
                                         text=', '.join(map(lambda x: '{:+f}'.format(x),
                                                            self.plotViewer.canvas.axes.get_ylim())))
        if not ok:
            return
        try:
            self.ylim = tuple(map(float, value.split(',')))
        except ValueError:
            QMessageBox.critical(self, 'Error', 'Invalid input.', QMessageBox.Ok)
            return

        self.plotViewer.canvas.axes.set_ylim(self.ylim)
        self.plotViewer.canvas.draw()

    def updateStats(self, ref_time, test_time):
        ewsd = np.array(list(self.ewsd.values()))
        quantile25, median, quantile75 = np.percentile(ewsd, [25, 50, 75])
        self.resultBox.appendPlainText(self.template.format(ref_time+1, test_time+1,
                                                            np.mean(ewsd), np.var(ewsd, ddof=1),
                                                            np.min(ewsd), quantile25, median,
                                                            quantile75, np.max(ewsd)))

    def updateHistogram(self):
        ewsd = list(self.ewsd.values())
        if self.xlim is not None:
            ewsd = list(filter(lambda x: self.xlim[0] <= x <= self.xlim[1], ewsd))

        weights = np.ones_like(ewsd) / self.input.ref_mesh.nb_triangles_inside  # make frequency histogram

        self.plotViewer.canvas.axes.clear()
        self.plotViewer.canvas.axes.grid(linestyle='dotted')

        self.plotViewer.canvas.axes.hist(ewsd, bins=settings.NB_BINS_EWSD, weights=weights, histtype='bar', color='g',
                                         edgecolor='k', alpha=0.5)
        self.plotViewer.canvas.axes.set_xlabel(self.plotViewer.current_xlabel)
        self.plotViewer.canvas.axes.set_ylabel(self.plotViewer.current_ylabel)
        self.plotViewer.canvas.axes.set_title(self.plotViewer.current_title)

        if self.ylim is not None:
            self.plotViewer.canvas.axes.set_ylim(self.ylim)

        self.plotViewer.canvas.draw()

        self.btnColorMap.setEnabled(True)
        self.XLimitsAct.setEnabled(True)
        self.YLimitsAct.setEnabled(True)

    def btnComputeEvent(self):
        self.xlim = None
        self.ylim = None
        self.has_map = False

        ref_time = int(self.timeSelection.refIndex.text()) - 1
        test_time = int(self.timeSelection.testIndex.text()) - 1
        selected_variable = self.input.varBox.currentText().split('(')[0][:-1]

        try:
            with Serafin.Read(self.input.ref_data.filename, self.input.ref_data.language) as input_stream:
                input_stream.header = self.input.ref_data.header
                input_stream.time = self.input.ref_data.time
                ref_values = input_stream.read_var_in_frame(ref_time, selected_variable)

            with Serafin.Read(self.input.test_data.filename, self.input.test_data.language) as input_stream:
                input_stream.header = self.input.test_data.header
                input_stream.time = self.input.test_data.time
                test_values = input_stream.read_var_in_frame(test_time, selected_variable)
        except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e:
            QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok)
            return

        values = test_values - ref_values
        self.ewsd = self.input.ref_mesh.element_wise_signed_deviation(values)

        self.updateStats(ref_time, test_time)
        self.updateHistogram()

    def btnColorMapEvent(self):
        if not self.has_map:
            reply = QMessageBox.question(self, 'Show distribution in 2D',
                                         'This may take some time. Are you sure to proceed?',
                                         QMessageBox.Yes | QMessageBox.No)
            if reply == QMessageBox.No:
                return
            selected_variable = self.input.varBox.currentText().split('(')[0][:-1]
            self.map.canvas.reinitFigure(self.input.ref_mesh, self.ewsd, selected_variable,
                                         self.xlim, self.input.ref_mesh.polygon)
            self.has_map = True
        self.btnColorMap.setEnabled(False)
        self.map.show()
class MergeCellsChanger(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        vbox = QVBoxLayout()

        hbox_col_bar = QHBoxLayout()
        lb_col_count = QLabel('병합할 열 개수 ', self)
        self.sb_col_count = QSpinBox(self)

        self.textarea = QPlainTextEdit(self)

        hbox_btn_bar = QHBoxLayout()
        btn_make = QPushButton(self)
        btn_clear = QPushButton(self)

        #setting Layout Box
        hbox_col_bar.addWidget(lb_col_count)
        hbox_col_bar.addWidget(self.sb_col_count)

        hbox_btn_bar.addWidget(btn_make)
        hbox_btn_bar.addWidget(btn_clear)

        vbox.addLayout(hbox_col_bar)
        vbox.addWidget(self.textarea)
        vbox.addLayout(hbox_btn_bar)

        # setting widget attribute
        self.sb_col_count.setMinimum(1)

        self.textarea.setPlaceholderText('내용 붙여넣기')
        self.textarea.setPlainText("")

        btn_make.setText('생성하기')
        btn_make.clicked.connect(self.make_excel)

        btn_clear.setText('내용 지우기')
        btn_clear.clicked.connect(lambda clear: self.textarea.clear())

        self.setLayout(vbox)
        self.setWindowTitle('QPushButton')
        self.center()
        self.show()

    # A 65 / a 97
    def make_excel(self):
        merged_col = self.sb_col_count.value()
        text = self.textarea.toPlainText().strip().split('\n')
        row_count = self.textarea.document().lineCount()  # 행 개수

        if text[0] == "":  # NULL
            QMessageBox.about(self, "오류", '내용을 입력하세요')
        else:  # Not NULL
            start_col = 1
            end_col = start_col + merged_col - 1

            # 엑셀 사용
            wb = openpyxl.Workbook()
            sheet = wb.active

            # 시트에 병합된 셀 동적 생성, 해당 셀에 값 넣기
            for i in range(0, row_count):
                sheet.merge_cells(start_row=i + 1,
                                  start_column=start_col,
                                  end_row=i + 1,
                                  end_column=end_col)
                sheet.cell(row=i + 1, column=1).value = text[i].strip()

            folder_path = ".\\MCC_Folder\\"
            filename = folder_path + "MCC.xlsx"  # .\\MCC_Folder\\MCC.xlsx
            tmp_filename = folder_path + "~$MCC.xlsx"

            if os.path.isdir(folder_path):  # 경로에 폴더 있을 시
                if os.path.isfile(tmp_filename):  # 파일 실행중일 때(~$ 임시 파일이 있을 시)
                    now = self.get_time()  # 현재시간
                    filename = folder_path + "MCC_%s.xlsx" % now  # 현재 시간으로 파일명 생성
            else:  # 경로에 폴더 없을 시 폴더 생성
                os.mkdir(folder_path)

            wb.save(filename)
            QMessageBox.about(self, "성공", "파일이 생성되었습니다")

    # 파일 저장할때 날짜 형식 가져오는 함수
    def get_time(self):
        now = time.strftime('%y%m%d_%H%M%S')
        return str(now)

    # gui 중앙 위치
    def center(self):
        # geometry of the main window
        qr = self.frameGeometry()

        # center point of screen
        cp = QDesktopWidget().availableGeometry().center()

        # move rectangle's center point to screen's center point
        qr.moveCenter(cp)

        # top left of rectangle becomes top left of window centering it
        self.move(qr.topLeft())
Example #21
0
class SubscriberWindow(QDialog):
    WINDOW_NAME_PREFIX = 'Subscriber'

    def __init__(self, parent, node, active_data_type_detector):
        super(SubscriberWindow, self).__init__(parent)
        self.setWindowTitle(self.WINDOW_NAME_PREFIX)
        self.setAttribute(Qt.WA_DeleteOnClose)              # This is required to stop background timers!

        self._node = node
        self._active_data_type_detector = active_data_type_detector
        self._active_data_type_detector.message_types_updated.connect(self._update_data_type_list)

        self._message_queue = queue.Queue()

        self._subscriber_handle = None

        self._update_timer = QTimer(self)
        self._update_timer.setSingleShot(False)
        self._update_timer.timeout.connect(self._do_redraw)
        self._update_timer.start(100)

        self._log_viewer = QPlainTextEdit(self)
        self._log_viewer.setReadOnly(True)
        self._log_viewer.setLineWrapMode(QPlainTextEdit.NoWrap)
        self._log_viewer.setFont(get_monospace_font())
        self._log_viewer.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        try:
            self._log_viewer.setPlaceholderText('Received messages will be printed here in YAML format')
        except AttributeError:      # Old PyQt
            pass

        self._num_rows_spinbox = QSpinBox(self)
        self._num_rows_spinbox.setToolTip('Number of rows to display; large number will impair performance')
        self._num_rows_spinbox.valueChanged.connect(
            lambda: self._log_viewer.setMaximumBlockCount(self._num_rows_spinbox.value()))
        self._num_rows_spinbox.setMinimum(1)
        self._num_rows_spinbox.setMaximum(1000000)
        self._num_rows_spinbox.setValue(100)

        self._num_errors = 0
        self._num_messages_total = 0
        self._num_messages_past_filter = 0

        self._msgs_per_sec_estimator = RateEstimator()

        self._num_messages_total_label = QuantityDisplay(self, 'Total', 'msgs')
        self._num_messages_past_filter_label = QuantityDisplay(self, 'Accepted', 'msgs')
        self._msgs_per_sec_label = QuantityDisplay(self, 'Accepting', 'msg/sec')

        self._type_selector = CommitableComboBoxWithHistory(self)
        self._type_selector.setToolTip('Name of the message type to subscribe to')
        self._type_selector.setInsertPolicy(QComboBox.NoInsert)
        completer = QCompleter(self._type_selector)
        completer.setCaseSensitivity(Qt.CaseSensitive)
        completer.setModel(self._type_selector.model())
        self._type_selector.setCompleter(completer)
        self._type_selector.on_commit = self._do_start
        self._type_selector.setFont(get_monospace_font())
        self._type_selector.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self._type_selector.setFocus(Qt.OtherFocusReason)

        self._active_filter = None
        self._filter_bar = FilterBar(self)
        self._filter_bar.on_filter = self._install_filter

        self._start_stop_button = make_icon_button('video-camera', 'Begin subscription', self, checkable=True,
                                                   on_clicked=self._toggle_start_stop)
        self._pause_button = make_icon_button('pause', 'Pause updates, non-displayed messages will be queued in memory',
                                              self, checkable=True)
        self._clear_button = make_icon_button('trash-o', 'Clear output and reset stat counters', self,
                                              on_clicked=self._do_clear)

        self._show_all_message_types = make_icon_button('puzzle-piece',
                                                        'Show all known message types, not only those that are '
                                                        'currently being exchanged over the bus',
                                                        self, checkable=True, on_clicked=self._update_data_type_list)

        layout = QVBoxLayout(self)

        controls_layout = QHBoxLayout(self)
        controls_layout.addWidget(self._start_stop_button)
        controls_layout.addWidget(self._pause_button)
        controls_layout.addWidget(self._clear_button)
        controls_layout.addWidget(self._filter_bar.add_filter_button)
        controls_layout.addWidget(self._show_all_message_types)
        controls_layout.addWidget(self._type_selector, 1)
        controls_layout.addWidget(self._num_rows_spinbox)

        layout.addLayout(controls_layout)
        layout.addWidget(self._filter_bar)
        layout.addWidget(self._log_viewer, 1)

        stats_layout = QHBoxLayout(self)
        stats_layout.addWidget(self._num_messages_total_label)
        stats_layout.addWidget(self._num_messages_past_filter_label)
        stats_layout.addWidget(self._msgs_per_sec_label)
        layout.addLayout(stats_layout)

        self.setLayout(layout)

        # Initial updates
        self._update_data_type_list()

    def _install_filter(self, f):
        self._active_filter = f

    def _apply_filter(self, yaml_message):
        """This function will throw if the filter expression is malformed!"""
        if self._active_filter is None:
            return True
        return self._active_filter.match(yaml_message)

    def _on_message(self, e):
        # Global statistics
        self._num_messages_total += 1

        # Rendering and filtering
        try:
            text = uavcan.to_yaml(e)
            if not self._apply_filter(text):
                return
        except Exception as ex:
            self._num_errors += 1
            text = '!!! [%d] MESSAGE PROCESSING FAILED: %s' % (self._num_errors, ex)
        else:
            self._num_messages_past_filter += 1
            self._msgs_per_sec_estimator.register_event(e.transfer.ts_monotonic)

        # Sending the text for later rendering
        try:
            self._message_queue.put_nowait(text)
        except queue.Full:
            pass

    def _toggle_start_stop(self):
        try:
            if self._subscriber_handle is None:
                self._do_start()
            else:
                self._do_stop()
        finally:
            self._start_stop_button.setChecked(self._subscriber_handle is not None)

    def _do_stop(self):
        if self._subscriber_handle is not None:
            self._subscriber_handle.remove()
            self._subscriber_handle = None

        self._pause_button.setChecked(False)
        self.setWindowTitle(self.WINDOW_NAME_PREFIX)

    def _do_start(self):
        self._do_stop()
        self._do_clear()

        try:
            selected_type = self._type_selector.currentText().strip()
            if not selected_type:
                return
            data_type = uavcan.TYPENAMES[selected_type]
        except Exception as ex:
            show_error('Subscription error', 'Could not load requested data type', ex, self)
            return

        try:
            self._subscriber_handle = self._node.add_handler(data_type, self._on_message)
        except Exception as ex:
            show_error('Subscription error', 'Could not create requested subscription', ex, self)
            return

        self.setWindowTitle('%s [%s]' % (self.WINDOW_NAME_PREFIX, selected_type))
        self._start_stop_button.setChecked(True)

    def _do_redraw(self):
        self._num_messages_total_label.set(self._num_messages_total)
        self._num_messages_past_filter_label.set(self._num_messages_past_filter)

        estimated_rate = self._msgs_per_sec_estimator.get_rate_with_timestamp()
        self._msgs_per_sec_label.set('N/A' if estimated_rate is None else ('%.0f' % estimated_rate[0]))

        if self._pause_button.isChecked():
            return

        self._log_viewer.setUpdatesEnabled(False)
        while True:
            try:
                text = self._message_queue.get_nowait()
            except queue.Empty:
                break
            else:
                self._log_viewer.appendPlainText(text + '\n')

        self._log_viewer.setUpdatesEnabled(True)

    def _update_data_type_list(self):
        logger.info('Updating data type list')
        if self._show_all_message_types.isChecked():
            items = self._active_data_type_detector.get_names_of_all_message_types_with_data_type_id()
        else:
            items = self._active_data_type_detector.get_names_of_active_messages()
        self._type_selector.clear()
        self._type_selector.addItems(items)

    def _do_clear(self):
        self._num_messages_total = 0
        self._num_messages_past_filter = 0
        self._do_redraw()
        self._log_viewer.clear()

    def closeEvent(self, qcloseevent):
        try:
            self._subscriber_handle.close()
        except Exception:
            pass
        super(SubscriberWindow, self).closeEvent(qcloseevent)

    @staticmethod
    def spawn(parent, node, active_data_type_detector):
        SubscriberWindow(parent, node, active_data_type_detector).show()
Example #22
0
class Dialog(QDialog):
    MESSAGE = "<p>Message boxes have a caption, a text, and up to three " \
            "buttons, each with standard or custom texts.</p>" \
            "<p>Click a button to close the message box. Pressing the Esc " \
            "button will activate the detected escape button (if any).</p>"

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

        self.openFilesPath = ''

        self.errorMessageDialog = QErrorMessage(self)

        frameStyle = QFrame.Sunken | QFrame.Panel

        self.issueLabel = QLabel()
        self.issueLabel.setFrameStyle(frameStyle)
        self.issueLabel = QLabel("Insert Issue id", self)

        self.issueText = QLineEdit()

        self.issueText = QLineEdit(self)

        self.openFileNameLabel = QLabel()
        self.openFileNameLabel.setFrameStyle(frameStyle)
        self.openFileNameButton = QPushButton("Browse File")

        self.newReqLabel = QLabel()
        self.newReqLabel.setFrameStyle(frameStyle)
        self.newReqLabel = QLabel("Insert Requirement", self)

        self.newReqText = QPlainTextEdit()
        self.newReqText.setFrameStyle(frameStyle)
        self.newReqText = QPlainTextEdit(self)

        self.addTable = QVBoxLayout()

        self.resultViewButton = QPushButton("View Result")

        self.addButton = QPushButton("Add")

        self.vizViewButton = QPushButton("View Visualizer")

        self.web = QWebEngineView()

        self.openFileNameButton.clicked.connect(self.setOpenFileName)

        self.resultViewButton.clicked.connect(self.setLabelResult)

        self.addButton.clicked.connect(self.storeResult)

        self.vizViewButton.clicked.connect(self.open_webbrowser)

        self.headline = QFont("Arial", 14, QFont.Bold)

        self.Issueidlabel = QLabel()
        self.Issueidlabel.setFrameStyle(frameStyle)
        self.Issueidlabel = QLabel("IssueID", self)
        self.Issueidlabel.setFont(self.headline)

        self.similaritylabel = QLabel()
        self.similaritylabel.setFrameStyle(frameStyle)
        self.similaritylabel = QLabel("Similarity", self)
        self.similaritylabel.setFont(self.headline)

        self.Requirementlabel = QLabel()
        self.Requirementlabel.setFrameStyle(frameStyle)
        self.Requirementlabel = QLabel("Requirement", self)
        self.Requirementlabel.setFont(self.headline)

        self.label1 = QLabel()
        self.label1.setFrameStyle(frameStyle)
        self.label1 = QLabel("", self)

        self.label2 = QLabel()
        self.label2.setFrameStyle(frameStyle)
        self.label2 = QLabel("", self)

        self.label3 = QLabel()
        self.label3.setFrameStyle(frameStyle)
        self.label3 = QLabel("", self)

        self.label4 = QLabel()
        self.label4.setFrameStyle(frameStyle)
        self.label4 = QLabel("", self)

        self.label5 = QLabel()
        self.label5.setFrameStyle(frameStyle)
        self.label5 = QLabel("", self)

        self.label6 = QLabel()
        self.label6.setFrameStyle(frameStyle)
        self.label6 = QLabel("", self)

        self.label7 = QLabel()
        self.label7.setFrameStyle(frameStyle)
        self.label7 = QLabel("", self)

        self.label8 = QLabel()
        self.label8.setFrameStyle(frameStyle)
        self.label8 = QLabel("", self)

        self.label9 = QLabel()
        self.label9.setFrameStyle(frameStyle)
        self.label9 = QLabel("", self)

        self.label10 = QLabel()
        self.label10.setFrameStyle(frameStyle)
        self.label10 = QLabel("", self)

        self.label11 = QLabel()
        self.label11.setFrameStyle(frameStyle)
        self.label11 = QLabel("", self)

        self.label12 = QLabel()
        self.label12.setFrameStyle(frameStyle)
        self.label12 = QLabel("", self)

        self.label13 = QLabel()
        self.label13.setFrameStyle(frameStyle)
        self.label13 = QLabel("", self)

        self.label14 = QLabel()
        self.label14.setFrameStyle(frameStyle)
        self.label14 = QLabel("", self)

        self.label15 = QLabel()
        self.label15.setFrameStyle(frameStyle)
        self.label15 = QLabel("", self)

        self.native = QCheckBox()
        self.native.setText("Use native file dialog.")
        self.native.setChecked(True)
        if sys.platform not in ("win32", "darwin"):
            self.native.hide()

        layout = QGridLayout()
        layout.setColumnStretch(1, 1)
        layout.setColumnMinimumWidth(1, 250)

        layout.addWidget(self.openFileNameButton, 6, 0)
        layout.addWidget(self.openFileNameLabel, 6, 1)

        layout.addWidget(self.issueLabel, 7, 0)
        layout.addWidget(self.issueText, 7, 1)

        layout.addWidget(self.web, 8, 1)
        layout.addWidget(self.newReqLabel, 9, 0)

        layout.addWidget(self.newReqText, 9, 1)

        layout.addWidget(self.resultViewButton, 11, 2)

        layout.addWidget(self.addButton, 11, 0)

        layout.addWidget(self.Issueidlabel, 15, 0)
        layout.addWidget(self.similaritylabel, 15, 1)
        layout.addWidget(self.Requirementlabel, 15, 2)

        layout.addWidget(self.label1, 16, 0)
        layout.addWidget(self.label2, 16, 1)
        layout.addWidget(self.label3, 16, 2)

        layout.addWidget(self.label4, 17, 0)
        layout.addWidget(self.label5, 17, 1)
        layout.addWidget(self.label6, 17, 2)

        layout.addWidget(self.label7, 18, 0)
        layout.addWidget(self.label8, 18, 1)
        layout.addWidget(self.label9, 18, 2)

        layout.addWidget(self.label10, 19, 0)
        layout.addWidget(self.label11, 19, 1)
        layout.addWidget(self.label12, 19, 2)

        layout.addWidget(self.label13, 20, 0)
        layout.addWidget(self.label14, 20, 1)
        layout.addWidget(self.label15, 20, 2)

        layout.addWidget(self.vizViewButton, 25, 0)

        width = 1000

        # setting  the fixed width of window
        self.setFixedWidth(width)

        self.setLayout(layout)

        self.setWindowTitle("Change Impact Analysis")

    def initUI(self):

        self.createTable()

        # Add box layout, add table to box layout and add box layout to widget
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.tableWidget)
        self.setLayout(self.layout)

        # Show widget
        self.show()

    def setExistingDirectory(self):
        options = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly
        directory = QFileDialog.getExistingDirectory(
            self,
            "QFileDialog.getExistingDirectory()",
            self.directoryLabel.text(),
            options=options)
        if directory:
            self.directoryLabel.setText(directory)

    def setOpenFileName(self):
        options = QFileDialog.Options()
        if not self.native.isChecked():
            options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            self.openFileNameLabel.text(),
            "All Files (*);;Text Files (*.txt)",
            options=options)
        if fileName:
            self.openFileNameLabel.setText(fileName)

    def storeResult(self):
        issueid = self.issueText.text()

        reqtext = self.newReqText.toPlainText()

        temp_filename = "temp.csv"

        pr.append(issueid, reqtext, temp_filename)
        self.issueText.clear()
        self.newReqText.clear()

    def setLabelResult(self):
        add = self.storeResult
        temp_filename = "temp.csv"
        df = pd.read_csv(temp_filename)
        for index, row in df.iterrows():
            print(row["Issue_key"], row["Requirement"])

            issueid = row["Issue_key"]

            reqtext = row["Requirement"]

            filename = self.openFileNameLabel.text()

            ending = filename.split('.')[-1]

            if ending == "csv":
                df = pd.read_csv(filename)
                df.to_csv(filename, index=False)

                # pr.append(issueid, reqtext, filename)

                file_uploaded = filename

                if not os.path.exists('docx'):
                    os.makedirs('docx')

                if not os.path.exists('txt'):
                    os.makedirs('txt')

                if not os.path.exists('candidates'):
                    os.makedirs('candidates')

                path = "docx/"
                pr.csvToDocx(filename)
                pr.convertDocxToText(path)
                filenames = os.listdir('./txt')
                pr.docToVec(filenames)
                cia_model = "sl_doc2vec.model"
                pr.vecToCsv(cia_model)
                result1 = pr.similarDocs(cia_model, reqtext)

                model_test = "clustering_model2.pkl"
                vecs = "vecs.csv"

                txt_folder = "txt/"
                candidates_fld = 'candidates/'

                result2 = pr.cluster(model_test, filename, vecs, txt_folder,
                                     candidates_fld, reqtext)

                pr.append(issueid, reqtext, filename)

                tableValues1 = []
                tableValues2 = []

                for i in result2[0]:
                    tableValues1.append(result2[1][i[0]])
                    tableValues2.append(str(i[1]))
                print("successfully finished!")
                filename = file_uploaded

                df = pd.read_csv(str(filename))

                content = []

                for f in df['Issue_key'].values:
                    for i in tableValues1:
                        if i in df['Issue_key'].values:
                            content.append(df.loc[df['Issue_key'] == i,
                                                  'Requirement'])

                from string import digits

                res = ''.join(filter(lambda x: not x.isdigit(), content[0]))

                self.label3.setText(res)

                self.label3.adjustSize()
                self.label3.setWordWrap(True)

                res2 = ''.join(filter(lambda x: not x.isdigit(), content[1]))
                self.label6.setText(res2)
                self.label6.adjustSize()
                self.label6.setWordWrap(True)

                res3 = ''.join(filter(lambda x: not x.isdigit(), content[2]))
                self.label9.setText(res3)
                self.label9.setWordWrap(True)
                res4 = ''.join(filter(lambda x: not x.isdigit(), content[3]))
                self.label12.setText(res4)
                self.label12.setWordWrap(True)

                res5 = ''.join(filter(lambda x: not x.isdigit(), content[4]))
                self.label15.setText(res5)
                self.label15.setWordWrap(True)

                self.label1.setText(tableValues1[0])
                self.label2.setText(tableValues2[0])

                self.label4.setText(tableValues1[1])
                self.label5.setText(tableValues2[1])

                self.label7.setText(tableValues1[2])
                self.label8.setText(tableValues2[2])

                self.label10.setText(tableValues1[3])
                self.label11.setText(tableValues2[3])

                self.label13.setText(tableValues1[4])
                self.label14.setText(tableValues2[4])

                fig = go.Figure(data=[
                    go.Table(columnorder=[1, 2, 3],
                             columnwidth=[80, 80, 400],
                             header=dict(values=[['<b>IssueId</b><br>'],
                                                 ['<b>Similarity</b>'],
                                                 ['<b>Requirement</b>']],
                                         line_color='darkslategray',
                                         fill_color='royalblue',
                                         align=['left', 'center'],
                                         font=dict(color='white', size=12),
                                         height=40))
                ])
            else:
                print("Problem detected with uploaded file")
        os.remove('temp.csv')

    def createTable(self):
        # Create table
        self.tableWidget = QTableWidget()
        self.tableWidget.setRowCount(4)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setItem(0, 0, QTableWidgetItem("Cell (1,1)"))
        self.tableWidget.setItem(0, 1, QTableWidgetItem("Cell (1,2)"))
        self.tableWidget.setItem(1, 0, QTableWidgetItem("Cell (2,1)"))
        self.tableWidget.setItem(1, 1, QTableWidgetItem("Cell (2,2)"))
        self.tableWidget.setItem(2, 0, QTableWidgetItem("Cell (3,1)"))
        self.tableWidget.setItem(2, 1, QTableWidgetItem("Cell (3,2)"))
        self.tableWidget.setItem(3, 0, QTableWidgetItem("Cell (4,1)"))
        self.tableWidget.setItem(3, 1, QTableWidgetItem("Cell (4,2)"))
        self.tableWidget.move(55, 70)

        # table selection change
        self.tableWidget.doubleClicked.connect(self.on_click)

    def open_webbrowser(self):
        webbrowser.open(
            'http://projector.tensorflow.org/?config=https://raw.githubusercontent.com/Bitseat/embeddings_projector/master/req_plot_config.json'
        )


#btn.clicked.connect(open_webbrowser)

    @pyqtSlot()
    def on_click(self):
        print("\n")
        for currentQTableWidgetItem in self.tableWidget.selectedItems():
            print(currentQTableWidgetItem.row(),
                  currentQTableWidgetItem.column(),
                  currentQTableWidgetItem.text())
Example #23
0
class ExampleWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = 'Proyecto Paradigmas'
        self.initUI()

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

        self.setMinimumSize(QSize(1310, 800))
        self.setWindowTitle("Proyecto Paradigmas")

        # Add text field
        self.b = QPlainTextEdit(self)
        self.b.insertPlainText("Definiciones y Reglas\n")
        self.b.move(10, 30)
        self.b.resize(900, 360)

        self.b.setStyleSheet("""QPlainTextEdit {background-color: #333;
                           color: #00FF00;
                           font-size: 20px;
                           font-family: Courier;}""")

        self.c = QPlainTextEdit(self)
        self.c.insertPlainText("Pruebas y Testeo.\n")
        self.c.move(10, 400)
        self.c.resize(640, 390)

        self.c.setStyleSheet("""QPlainTextEdit {background-color: #333;
                           color: #00FF00;
                           font-size: 20px;
                           font-family: Courier;}""")

        self.d = QPlainTextEdit(self)
        self.d.insertPlainText("Resultado de la ejecución.\n")
        self.d.move(660, 400)
        self.d.resize(640, 390)
        self.d.setReadOnly(True)

        self.d.setStyleSheet("""QPlainTextEdit {background-color: #333;
                           color: #00FF00;
                           font-size: 20px;
                           font-family: Courier;}""")

        #Menu bar
        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu('Archivo')
        ejecutar = mainMenu.addMenu('Ejecutar')
        helpMenu = mainMenu.addMenu('Help')

        abrir = QAction(QIcon('exit24.png'), 'Abrir TXT', self)
        abrir.triggered.connect(self.leerArchivo)
        fileMenu.addAction(abrir)

        abrir2 = QAction(QIcon('exit24.png'), 'Abrir XML', self)
        abrir2.triggered.connect(self.leerArchivo2)
        fileMenu.addAction(abrir2)

        guardar = QAction(QIcon('exit24.png'), 'Guardar TXT', self)
        guardar.triggered.connect(self.guardarArchivo)
        fileMenu.addAction(guardar)

        guardar2 = QAction(QIcon('exit24.png'), 'Guardar XML', self)
        guardar2.triggered.connect(self.guardarArchivo2)
        fileMenu.addAction(guardar2)

        cargar = QAction(QIcon('exit24.png'), 'Cargar Hileras', self)
        cargar.triggered.connect(self.cargarHileras)
        fileMenu.addAction(cargar)

        exitButton = QAction(QIcon('exit24.png'), 'Exit', self)
        exitButton.setShortcut('Ctrl+Q')
        exitButton.setStatusTip('Exit application')
        exitButton.triggered.connect(self.close)
        fileMenu.addAction(exitButton)

        paso = QAction(QIcon('exit24.png'), 'Paso a Paso', self)
        ejecutar.addAction(paso)

        correr = QAction(QIcon('exit24.png'), 'Correr', self)
        ejecutar.addAction(correr)

        button = QPushButton('α', self)
        button.setToolTip('Este es el botón de alpha')
        button.move(910, 30)
        button.resize(190, 50)
        button.clicked.connect(self.on_click)

        button2 = QPushButton('β', self)
        button2.setToolTip('Este es el botón de beta')
        button2.move(1110, 30)
        button2.resize(190, 50)
        button2.clicked.connect(self.on_click2)

        button3 = QPushButton('γ', self)
        button3.setToolTip('Este es el botón de gamma')
        button3.move(910, 80)
        button3.resize(190, 50)
        button3.clicked.connect(self.on_click3)

        button4 = QPushButton('δ', self)
        button4.setToolTip('Este es el botón de delta')
        button4.move(1110, 80)
        button4.resize(190, 50)
        button4.clicked.connect(self.on_click4)

        button5 = QPushButton('ε', self)
        button5.setToolTip('Este es el botón de epsilon')
        button5.move(910, 130)
        button5.resize(190, 50)
        button5.clicked.connect(self.on_click5)

        button6 = QPushButton('ζ', self)
        button6.setToolTip('Este es el botón de dzeta')
        button6.move(1110, 130)
        button6.resize(190, 50)
        button6.clicked.connect(self.on_click6)

        button7 = QPushButton('η', self)
        button7.setToolTip('Este es el botón de eta')
        button7.move(910, 180)
        button7.resize(190, 50)
        button7.clicked.connect(self.on_click7)

        button8 = QPushButton('θ', self)
        button8.setToolTip('Este es el botón de theta')
        button8.move(1110, 180)
        button8.resize(190, 50)
        button8.clicked.connect(self.on_click8)

        button9 = QPushButton('λ', self)
        button9.setToolTip('Este es el botón de lambda')
        button9.move(910, 230)
        button9.resize(190, 50)
        button9.clicked.connect(self.on_click9)

        button10 = QPushButton('μ', self)
        button10.setToolTip('Este es el botón de mi')
        button10.move(1110, 230)
        button10.resize(190, 50)
        button10.clicked.connect(self.on_click10)

        button11 = QPushButton('ξ', self)
        button11.setToolTip('Este es el botón de xi')
        button11.move(910, 280)
        button11.resize(190, 50)
        button11.clicked.connect(self.on_click11)

        button12 = QPushButton('π', self)
        button12.setToolTip('Este es el botón de pi')
        button12.move(1110, 280)
        button12.resize(190, 50)
        button12.clicked.connect(self.on_click12)

        button13 = QPushButton('φ', self)
        button13.setToolTip('Este es el botón de phi')
        button13.move(910, 330)
        button13.resize(190, 60)
        button13.clicked.connect(self.on_click13)

        button14 = QPushButton('Ω', self)
        button14.setToolTip('Este es el botón de omega')
        button14.move(1110, 330)
        button14.resize(190, 60)
        button14.clicked.connect(self.on_click14)

        stl = """QPushButton {
        background-color: #333;
        border-width: 2px;
        border-color: #00FF00;
        color: #00FF00;
        font-size: 30px;
        font-family: Courier;
        border-style: solid;
        }"""

        QApplication.instance().setStyleSheet(stl)

        self.show()

    @pyqtSlot()
    def on_click(self):
        print('Botón de alpha')
        self.b.insertPlainText('α')

    @pyqtSlot()
    def on_click2(self):
        print('Botón de beta')
        self.b.insertPlainText('β')

    @pyqtSlot()
    def on_click3(self):
        print('Botón de gamma')
        self.b.insertPlainText('γ')

    @pyqtSlot()
    def on_click4(self):
        print('Botón de delta')
        self.b.insertPlainText('δ')

    @pyqtSlot()
    def on_click5(self):
        print('Botón de epsilon')
        self.b.insertPlainText('ε')

    @pyqtSlot()
    def on_click6(self):
        print('Botón de dzeta')
        self.b.insertPlainText('ζ')

    @pyqtSlot()
    def on_click7(self):
        print('Botón de eta')
        self.b.insertPlainText('η')

    @pyqtSlot()
    def on_click8(self):
        print('Botón de theta')
        self.b.insertPlainText('θ')

    @pyqtSlot()
    def on_click9(self):
        print('Botón de lambda')
        self.b.insertPlainText('λ')

    @pyqtSlot()
    def on_click10(self):
        print('Botón de mi')
        self.b.insertPlainText('μ')

    @pyqtSlot()
    def on_click11(self):
        print('Botón de xi')
        self.b.insertPlainText('ξ')

    @pyqtSlot()
    def on_click12(self):
        print('Botón de pi')
        self.b.insertPlainText('π')

    @pyqtSlot()
    def on_click13(self):
        print('Botón de phi')
        self.b.insertPlainText('φ')

    @pyqtSlot()
    def on_click14(self):
        print('Botón de omega')
        self.b.insertPlainText('Ω')

    def guardarArchivo(self):
        print('Guardando TXT')
        texto = self.b.toPlainText()
        direccion = self.saveFileDialog()
        if (not (direccion is 'nulo')):
            direccion = direccion + '.txt'
            f = open(direccion, 'w')
            f.write(texto)
            f.close()
        else:
            print('El usuario canceló la operación')

    def guardarArchivo2(self):
        print('Guardando XML')
        texto = self.b.toPlainText()
        direccion = self.saveFileDialog()
        if (not (direccion is 'nulo')):
            root = ET.Element("root")
            doc = ET.SubElement(root, "doc")
            nodo1 = ET.SubElement(doc, "nodo1", name="nodo")
            nodo1.text = texto
            arbol = ET.ElementTree(root)
            direccion = direccion + '.xml'
            arbol.write(direccion)
        else:
            print('El usuario canceló la operación')

    def leerArchivo(self):
        print('Leyendo TXT')
        direccion = self.openFileNameDialogTXT()
        if (not (direccion is 'nulo')):
            f = open(direccion, 'r')
            mensaje = f.read()
            self.b.clear()
            self.b.insertPlainText(mensaje)
            f.close()
        else:
            print('El usuario canceló la operación')

    def leerArchivo2(self):
        print('Leyendo XML')
        direccion = self.openFileNameDialogXML()
        if (not (direccion is 'nulo')):
            mydoc = minidom.parse(direccion)
            items = mydoc.getElementsByTagName('nodo1')
            print('Item 1 attribute:')
            print(items[0].attributes['name'].value)
            print(items[0].firstChild.data)
            self.b.clear()
            mensaje = items[0].firstChild.data
            self.b.insertPlainText(mensaje)
        else:
            print('El usuario canceló la operación')

    def cargarHileras(self):
        print('Cargando Hileras')
        direccion = self.openFileNameDialogTXT()
        if (not (direccion is 'nulo')):
            f = open(direccion, 'r')
            mensaje = f.read()
            self.c.clear()
            self.c.insertPlainText(mensaje)
            f.close()
        else:
            print('El usuario canceló la operación')

    def openFileNameDialogTXT(self):
        textoAuxiliar = 'nulo'
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            "",
            "Text Files (*.txt)",
            options=options)
        if fileName:
            #print(fileName)
            textoAuxiliar = fileName
        print(textoAuxiliar)
        return textoAuxiliar

    def openFileNameDialogXML(self):
        textoAuxiliar = 'nulo'
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            "",
            "XML Files (*.xml)",
            options=options)
        if fileName:
            #print(fileName)
            textoAuxiliar = fileName
        print(textoAuxiliar)
        return textoAuxiliar

    def saveFileDialog(self):
        textoAuxiliar = 'nulo'
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getSaveFileName(
            self,
            "QFileDialog.getSaveFileName()",
            "",
            "All Files (*);;Text Files (*.txt)",
            options=options)
        if fileName:
            #print(fileName)
            textoAuxiliar = fileName
        print(textoAuxiliar)
        return textoAuxiliar
class MigrationWidget(QWidget):

    def __init__(self):
        super(MigrationWidget, self).__init__()
        self._migration = {}
        vbox = QVBoxLayout(self)
        lbl_title = QLabel(_translate("MigrationWidget", "Current code:"))
        self.current_list = QListWidget()
        lbl_suggestion = QLabel(_translate("MigrationWidget", "Suggested changes:"))
        self.suggestion = QPlainTextEdit()
        self.suggestion.setReadOnly(True)

        self.btn_apply = QPushButton(_translate("MigrationWidget", "Apply change!"))
        hbox = QHBoxLayout()
        hbox.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding))
        hbox.addWidget(self.btn_apply)

        vbox.addWidget(lbl_title)
        vbox.addWidget(self.current_list)
        vbox.addWidget(lbl_suggestion)
        vbox.addWidget(self.suggestion)
        vbox.addLayout(hbox)

        self.current_list.itemClicked['QListWidgetItem*'].connect(self.load_suggestion)
        self.btn_apply.clicked['bool'].connect(self.apply_changes)

    def apply_changes(self):
        lineno = int(self.current_list.currentItem().data(Qt.UserRole))
        lines = self._migration.migration_data[lineno][0].split('\n')
        remove = -1
        code = ''
        for line in lines:
            if line.startswith('-'):
                remove += 1
            elif line.startswith('+'):
                code += '%s\n' % line[1:]

        editorWidget = main_container.MainContainer().get_actual_editor()
        block_start = editorWidget.document().findBlockByLineNumber(lineno)
        block_end = editorWidget.document().findBlockByLineNumber(
            lineno + remove)
        cursor = editorWidget.textCursor()
        cursor.setPosition(block_start.position())
        cursor.setPosition(block_end.position(), QTextCursor.KeepAnchor)
        cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
        cursor.insertText(code[:-1])

    def load_suggestion(self, item):
        lineno = int(item.data(Qt.UserRole))
        lines = self._migration.migration_data[lineno][0].split('\n')
        code = ''
        for line in lines:
            if line.startswith('+'):
                code += '%s\n' % line[1:]
        self.suggestion.setPlainText(code)
        editorWidget = main_container.MainContainer().get_actual_editor()
        if editorWidget:
            editorWidget.jump_to_line(lineno)
            editorWidget.setFocus()

    def refresh_lists(self, migration):
        self._migration = migration
        self.current_list.clear()
        base_lineno = -1
        for lineno in sorted(migration.migration_data.keys()):
            linenostr = 'L%s\n' % str(lineno + 1)
            data = migration.migration_data[lineno]
            lines = data[0].split('\n')
            if base_lineno == data[1]:
                continue
            base_lineno = data[1]
            message = ''
            for line in lines:
                if line.startswith('-'):
                    message += '%s\n' % line
            item = QListWidgetItem(linenostr + message)
            item.setToolTip(linenostr + message)
            item.setData(Qt.UserRole, lineno)
            self.current_list.addItem(item)

    def clear(self):
        """
        Clear the widget
        """
        self.current_list.clear()
        self.suggestion.clear()
Example #25
0
class Summarizer(QWidget):

    # Declaring
    def __init__(self):
        super().__init__()

        self.layout = None
        self.label = None
        self.input_text = None
        self.summarize_button = None
        self.output_text = None

        self.init_ui()

    # initializing UI
    def init_ui(self):

        # Main window
        self.setGeometry(800, 800, 800, 800)
        self.setWindowTitle('Text Summarizer')
        self.layout = QVBoxLayout()

        # Input text box
        self.input_text = QPlainTextEdit()
        self.input_text.insertPlainText("Enter your text here...")
        self.input_text.resize(50, 50)
        self.layout.addWidget(self.input_text)

        # Push Button
        self.summarize_button = QPushButton("Summarize")
        self.layout.addWidget(self.summarize_button)

        # Text Output
        self.output_text = QPlainTextEdit()
        self.output_text.insertPlainText("Summarized text...")
        self.output_text.setReadOnly(True)
        self.output_text.resize(50, 50)
        self.layout.addWidget(self.output_text)

        self.setLayout(self.layout)

        self.summarize_button.clicked.connect(self.summarize)

    # Show UI
    def run(self):
        self.show()

    # Summarizer
    def summarize(self):
        txt = self.input_text.toPlainText()
        print(txt)

        parser = None

        # Testing summarizer and checking for errors
        try:
            parser = PlaintextParser.from_string(txt, Tokenizer("english"))
            print("summarizing")
            summarizer = LexRankSummarizer()
            print("summarizing")
            summary = summarizer(parser.document, 4)
            self.output_text.clear()
            for sentence in summary:
                print(sentence)
                self.output_text.insertPlainText(str(sentence))
        except Exception as err:
            print("ERROR: " + str(err))
        finally:
            print("finally")
class App(QWidget):

    USs = []  # { F# , name , description , Acceptance Criteria }
    USNames = []  # user stories names
    TCs = []  # { TC name , TC description }

    def __init__(self):
        super().__init__()
        self.title = 'NLP project.'
        self.left = 50
        self.top = 50
        self.width = 1500
        self.height = 800
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)

        # Create Label
        label = QLabel('Select User Story by name:', self)
        label.move(50, 0)

        # Create Label
        label2 = QLabel('US Description + Acceptance Criteria:', self)
        label2.move(50, 125)

        # Create Label
        label3 = QLabel('Choose Algorithm:', self)
        label3.move(50, 600)

        # Create Label
        label4 = QLabel('Results:', self)
        label4.move(1000, 50)

        # Create textbox user story
        self.textbox = QPlainTextEdit(self)
        self.textbox.move(50, 175)
        self.textbox.resize(500, 300)
        """
        # Create textbox results
        self.textbox3 = QLineEdit(self)
        self.textbox3.move(1000, 75)
        self.textbox3.resize(400,600)
        self.textbox3.setDisabled(True)
        """

        self.tableWidget = QTableWidget()

        #self.tableWidget.resize(400,600)

        # Create textbox tokenize

        self.textbox4 = QLineEdit(self)
        self.textbox4.move(50, 700)
        self.textbox4.resize(280, 40)
        #self.textbox4.setDisabled(True)
        """
        self.scrollArea = QScrollArea(self)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.move(50,400)
        self.scrollArea.resize(280,40)
        self.scrollArea.setWidget(self.textbox4)
        """
        button = QPushButton('Start', self)
        button.move(150, 750)
        button.clicked.connect(self.on_click_start)

        button2 = QPushButton('Tokenize', self)
        button2.move(50, 625)
        button2.clicked.connect(self.on_click_tokenize)

        button3 = QPushButton('Load excel', self)
        button3.move(50, 750)
        button3.clicked.connect(self.on_click_load)

        button4 = QPushButton('Choose US', self)
        button4.move(550, 29)
        button4.clicked.connect(self.on_click_choose_US)

        button5 = QPushButton('Choose AC', self)
        button5.move(550, 149)
        button5.clicked.connect(self.on_click_choose_AC)

        button6 = QPushButton('Clear', self)
        button6.move(250, 750)
        button6.clicked.connect(self.on_click_clear)

        # algorithm combobox
        self.comboBox = QComboBox(self)
        algorithms = ['cosine', 'other']
        self.comboBox.addItems(algorithms)
        self.comboBox.move(150, 625)

        # US combobox
        self.comboBox2 = QComboBox(self)
        self.comboBox2.move(50, 25)
        self.comboBox2.resize(500, 20)
        #action_relect = lambda: self.on_click_reselect_us(self)
        self.comboBox2.currentIndexChanged.connect(self.on_click_reselect_us)

        # AC combobox
        self.comboBox3 = QComboBox(self)
        self.comboBox3.move(50, 150)
        self.comboBox3.resize(500, 20)

        self.show()

    @pyqtSlot()
    def on_click_reselect_us(self):

        self.textbox.clear()
        self.comboBox3.clear()

    @pyqtSlot()
    def on_click_clear(self):

        self.textbox.clear()
        self.textbox3.clear()
        self.textbox4.clear()
        self.comboBox.clear()
        self.comboBox2.clear()
        self.comboBox3.clear()

    @pyqtSlot()
    def on_click_start(self):

        us = self.textbox2.text()
        results = []
        for tc in self.TCs:
            tmp = tc[0] + tc[1]
            results.append({
                'match_sentence': tmp,
                'score': compare_sens(us, tmp)
            })

        i = 0
        self.tableWidget.setSortingEnabled(True)
        self.tableWidget.setRowCount(100)
        self.tableWidget.setColumnCount(2)
        results = sorted(results, key=itemgetter('score'), reverse=True)

        for res in results:
            #self.tableWidget.insertRow(str(res)+str1)
            #self.tableWidget.setItem(i,0, QTableWidgetItem(str(res[1])))
            self.tableWidget.setItem(i, 0, QTableWidgetItem(str(res)))
            i += 1
            #self.textbox3.insert(str(res)+str1
        self.tableWidget.move(1000, 75)
        self.tableWidget.show()

    @pyqtSlot()
    def on_click_choose_US(self):

        # set User Story over textbox so we can edit if needed
        text = self.comboBox2.currentText()
        self.textbox.setPlainText(text)
        self.textbox.show()

        #  fill AC combobox
        descriptions = []
        ACs = []
        tmp = []
        us = self.comboBox2.currentText()

        for a, b, c, d in self.USs:
            if b == us:
                descriptions.append(c)
                ACs.append(d)
                tmp.append(c + d)
        self.comboBox3.addItems(tmp)

    @pyqtSlot()
    def on_click_choose_AC(self):

        # set AC over textbox so we can edit if needed
        text = self.comboBox3.currentText()
        self.textbox.paste()
        self.textbox.show()

    @pyqtSlot()
    def on_click_tokenize(self):

        text = self.textbox.text()
        tok = str(tokenize(text))
        self.textbox4.setText(tok)

    @pyqtSlot()
    def on_click_load(self):

        # Assign spreadsheet filename to `file`
        file = self.openFileNameDialog()

        # Load in the workbook
        wb = load_workbook(file)

        # Get sheet names
        data_sheets_names = wb.sheetnames
        print(wb.sheetnames)

        # Get all the sheet names that hold User stories and Test Cases
        USs_sheets_names = []
        TCs_Sheets_names = []

        for sheet_name in data_sheets_names:
            if sheet_name.find("TCs") != -1:
                TCs_Sheets_names.append(sheet_name)
            if sheet_name.find(" F") != -1:
                USs_sheets_names.append(sheet_name)

        # get NLP data sheets
        for name in USs_sheets_names:
            sheet = wb[name]
            for i in range(2, sheet.max_row + 1):
                self.USs.append(
                    ((sheet.cell(i, 1).value), (sheet.cell(i, 2).value),
                     (sheet.cell(i, 3).value), (sheet.cell(i, 4).value)))
            self.USNames.append((sheet.cell(2, 2).value))

        for name in TCs_Sheets_names:
            sheet = wb[name]
            for i in range(2, sheet.max_row + 1):
                self.TCs.append(
                    (name, (sheet.cell(i, 1).value), (sheet.cell(i, 2).value)))

        #remove doubles
        self.USNames = list(set(self.USNames))
        self.comboBox2.addItems(self.USNames)

        print(self.USNames)

    def openFileNameDialog(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            "",
            "All Files (*);;Excel Files (*.xlsx)",
            options=options)
        if fileName:
            print(fileName)
        return fileName
class ComputeErrorsTab(QWidget):
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab
        self.timeSelection = DoubleTimeSelection()
        self.btnCompute = QPushButton('Compute', icon=self.style().standardIcon(QStyle.SP_DialogApplyButton))
        self.btnCompute.setFixedSize(105, 50)
        self.resultTextBox = QPlainTextEdit()

        self.btnCompute.clicked.connect(self.btnComputeEvent)

        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.addWidget(self.timeSelection)
        mainLayout.addItem(QSpacerItem(10, 10))
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.btnCompute)
        hlayout.setAlignment(self.btnCompute, Qt.AlignTop)
        hlayout.setAlignment(Qt.AlignHCenter)
        vlayout = QVBoxLayout()
        vlayout.addWidget(self.resultTextBox)
        hlayout.addItem(QSpacerItem(10, 1))
        hlayout.addLayout(vlayout)
        mainLayout.addLayout(hlayout)
        self.setLayout(mainLayout)

        self.template = '=== Comparison between Ref (frame {}) and Test (frame {}) ===\n'\
                        'MSD  (Mean signed deviation)         \t{:<30}\n' \
                        'MAD  (Mean absolute deviation)       \t{:<30}\n' \
                        'RMSD (Root mean square deviation)    \t{:<30}\n'

    def add_reference(self):
        self.timeSelection.initRef(self.input.ref_data.header.nb_frames)

    def add_test(self):
        self.timeSelection.initTest(self.input.test_data.header.nb_frames)

    def reset(self):
        self.timeSelection.clearText()
        self.resultTextBox.clear()

    def btnComputeEvent(self):
        ref_time = int(self.timeSelection.refIndex.text()) - 1
        test_time = int(self.timeSelection.testIndex.text()) - 1
        selected_variable = self.input.varBox.currentText().split('(')[0][:-1]

        try:
            with Serafin.Read(self.input.ref_data.filename, self.input.ref_data.language) as input_stream:
                input_stream.header = self.input.ref_data.header
                input_stream.time = self.input.ref_data.time
                ref_values = input_stream.read_var_in_frame(ref_time, selected_variable)

            with Serafin.Read(self.input.test_data.filename, self.input.test_data.language) as input_stream:
                input_stream.header = self.input.test_data.header
                input_stream.time = self.input.test_data.time
                test_values = input_stream.read_var_in_frame(test_time, selected_variable)
        except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e:
            QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok)
            return

        values = test_values - ref_values
        msd = self.input.ref_mesh.mean_signed_deviation(values)
        mad = self.input.ref_mesh.mean_absolute_deviation(values)
        rmsd = self.input.ref_mesh.root_mean_square_deviation(values)
        self.resultTextBox.appendPlainText(self.template.format(ref_time+1, test_time+1, msd, mad, rmsd))
Example #28
0
class PluginDialog(AppletDialog):
    aboutToClose = pyqtSignal()
    messageToTeletext = pyqtSignal(str)
    switchLed = pyqtSignal(str, str)

    # __________________________________________________________________
    def __init__(self, title, icon, logger):
        super().__init__(title, icon, logger)

        # always on top sometimes doesn't work
        self.setAttribute(Qt.WA_AlwaysStackOnTop)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint | Qt.WindowStaysOnTopHint)

    # __________________________________________________________________
    def _buildUi(self):
        self._clues = {}
        self._selectionComboBox = None
        self.loadLanguage()
        self.loadClueAlbum('clue-album.ini')

        if self._clues:
            self._selectionComboBox = QComboBox()
            self._selectionComboBox.addItem(self.tr("Load clue..."), None)
            for k in self._clues:
                clue = self._clues[k]
                self._selectionComboBox.addItem(clue.title, k)

        self._options = {}
        if os.path.isfile('definitions.ini'):
            definitions = QSettings('definitions.ini', QSettings.IniFormat)
            for group in definitions.childGroups():
                definitions.beginGroup(group)
                if group == "options":
                    for key in definitions.childKeys():
                        self._options[key] = definitions.value(key)
                definitions.endGroup()

        main_layout = QVBoxLayout()
        main_layout.setSpacing(12)

        self._led = LedWidget(self.tr("Raspberry Teletext"), QSize(40, 20))
        self._led.setRedAsBold(True)
        self._led.setRedAsRed(True)
        self._led.switchOn('gray')

        settings_button = QPushButton()
        settings_button.setIcon(QIcon("./settings.svg"))
        settings_button.setFlat(True)
        settings_button.setToolTip(self.tr("Effects and language"))
        settings_button.setIconSize(QSize(16, 16))
        settings_button.setFixedSize(QSize(24, 24))

        header_layout = QHBoxLayout()
        header_layout.addWidget(self._led)
        header_layout.addWidget(settings_button, Qt.AlignRight)
        main_layout.addLayout(header_layout)

        stop_button = QPushButton()
        stop_button.setIcon(QIcon("./cancel.svg"))
        stop_button.setFlat(True)
        stop_button.setToolTip(self.tr("Clear TV screen"))
        stop_button.setIconSize(QSize(16, 16))
        stop_button.setFixedSize(QSize(24, 24))

        if 'tv-screen-width' in self._options and 'tv-screen-height' in self._options:
            hint = QSize(int(self._options['tv-screen-width']), int(self._options['tv-screen-height']))
            # self._tvScreen = TvScreenLabel(self.tr("<div align=center>Display on TV</div>"), hint)
            self._tvScreen = TvScreenLabel('', hint)
            policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        else:
            # self._tvScreen = TvScreenLabel(self.tr("<div align=center>Display on TV</div>"))
            self._tvScreen = TvScreenLabel('')
            policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        policy.setHeightForWidth(True)
        self._tvScreen.setSizePolicy(policy)

        display_layout = QHBoxLayout()
        display_layout.addWidget(self._tvScreen)
        display_layout.addStretch()
        display_layout.addWidget(stop_button, Qt.AlignRight)
        main_layout.addLayout(display_layout)

        if self._selectionComboBox:
            main_layout.addWidget(self._selectionComboBox)

        self._editor = QPlainTextEdit()
        self._editor.setFrameShape(QFrame.NoFrame)
        self._editor.setCursorWidth(8)
        main_layout.addWidget(self._editor)

        clear_button = QPushButton(self.tr("Erase draft"))
        clear_button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)

        send_button = QPushButton(self.tr("Display on TV"))
        send_button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)

        button_layout = QHBoxLayout()
        button_layout.addWidget(send_button)
        button_layout.addWidget(clear_button)
        main_layout.addLayout(button_layout)

        self.setLayout(main_layout)

        settings_button.pressed.connect(self.settings)
        stop_button.pressed.connect(self.stop)
        clear_button.pressed.connect(self.erase)
        send_button.pressed.connect(self.send)
        self.switchLed.connect(self._led.switchOn)
        if self._selectionComboBox:
            self._selectionComboBox.activated.connect(self.selectClue)

        self._editor.setFocusPolicy(Qt.StrongFocus)
        self._editor.setFocus(Qt.OtherFocusReason)

    # __________________________________________________________________
    @pyqtSlot(str)
    def onTeletextDisplayMessage(self, message):
        if message == "-":
            message = ""
        message = message.replace('\n', '<br>')
        self._tvScreen.setText('<div style="text-align:center">' + message + '</div>')

    # __________________________________________________________________
    @pyqtSlot(str)
    def onPropsMessage(self, message):
        if message.startswith("DISCONNECTED"):
            self._tvScreen.setText("")
            self._led.switchOn('yellow')
        else:
            if self._led.color() != 'green':
                self._led.switchOn('green')

    # __________________________________________________________________
    def closeEvent(self, e):
        self.aboutToClose.emit()

    # __________________________________________________________________
    @pyqtSlot()
    def erase(self):
        self._selectionComboBox.setCurrentIndex(0)
        self._editor.clear()

    # __________________________________________________________________
    def loadClueAlbum(self, filename):
        # keys with ',' are read as list and will be joined back
        if os.path.isfile(filename):
            album = QSettings(filename, QSettings.IniFormat)
            album.setIniCodec("UTF-8");
            for group in album.childGroups():
                album.beginGroup(group)
                key = group
                if not 'fr' in album.childKeys():
                    self._logger.warning(
                        "{} [{}] : {}".format(self.tr("Clue"), group, self.tr("ignored because 'fr' is missing")))
                    continue
                if not 'en' in album.childKeys():
                    self._logger.warning(
                        "{} [{}] : {}".format(self.tr("Clue"), group, self.tr("ignored because 'en' is missing")))
                    continue
                try:
                    title = album.value('en')
                    if '|' in title:
                        en = re.compile(r'\s*\|\s*').split(title)
                    else:
                        en = (title, '')
                    text = album.value('fr')
                    if '|' in text:
                        fr = re.compile(r'\s*\|\s*').split(text)
                    else:
                        fr = (text, '')
                    self._clues[key] = Clue(title, fr, en)
                except:
                    self._logger.warning("{} {}".format(self.tr("Failed to load clue : "), key))
                album.endGroup()

    # __________________________________________________________________
    @pyqtSlot()
    def loadLanguage(self):
        settings = QSettings("settings.ini", QSettings.IniFormat);
        settings.setIniCodec("UTF-8");
        settings.beginGroup("Cues")
        self._language = settings.value("language", "fr")
        settings.endGroup()

        if self._selectionComboBox:
            self.selectClue(self._selectionComboBox.currentIndex())

    # __________________________________________________________________
    @pyqtSlot('int')
    def selectClue(self, index):
        try:
            k = self._selectionComboBox.itemData(index)
            if k:
                self._editor.clear()
                clue = self._clues[k]
                if self._language == "fr":
                    text1, text2 = clue.fr
                else:
                    text1, text2 = clue.en
                if text2:
                    self._editor.insertPlainText(text1 + '\n' + text2)
                else:
                    self._editor.insertPlainText(text1)
                self._editor.setFocus(Qt.OtherFocusReason)
        except:
            self._logger.warning("{} {}".format(self.tr("Failed to select clue : index"), index))

    # __________________________________________________________________
    @pyqtSlot()
    def send(self):
        message = self._editor.toPlainText().strip()
        if len(message):
            self.messageToTeletext.emit("display:" + message)
        self._selectionComboBox.setCurrentIndex(0)
        self._editor.clear()

    # __________________________________________________________________
    @pyqtSlot(str)
    def setLanguage(self, lang):
        self._logger.info(self.tr("Request received : language in ") + lang)

        if lang in ["en", "fr"]:
            self._language = lang

            settings = QSettings("settings.ini", QSettings.IniFormat);
            settings.setIniCodec("UTF-8");
            settings.beginGroup("Cues")
            settings.setValue("language", self._language)
            settings.endGroup()
            settings.sync()

            if self._selectionComboBox:
                self.selectClue(self._selectionComboBox.currentIndex())

    # __________________________________________________________________
    @pyqtSlot()
    def settings(self):
        dlg = PluginSettingsDialog(self._logger)
        dlg.setModal(True)
        dlg.move(self.pos() + QPoint(20, 20))
        dlg.languageChanged.connect(self.loadLanguage)
        dlg.messageToTeletext.connect(self.messageToTeletext)
        dlg.exec()

    # __________________________________________________________________
    @pyqtSlot()
    def stop(self):
        self.messageToTeletext.emit("erase")
class BSSTab(QWidget):
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab
        self.timeSelection = DoubleTimeSelection()
        self.initSelection = SimpleTimeSelection('Initial state index')

        # set up a custom plot viewer
        self.has_figure = False
        self.plotViewer = PlotViewer()
        self.plotViewer.exitAct.setEnabled(False)
        self.plotViewer.menuBar.setVisible(False)
        self.plotViewer.toolBar.addAction(self.plotViewer.xLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.yLabelAct)
        self.plotViewer.toolBar.addSeparator()
        self.plotViewer.toolBar.addAction(self.plotViewer.titleAct)
        self.plotViewer.canvas.figure.canvas.mpl_connect('motion_notify_event', self.plotViewer.mouseMove)
        self.initSelection.refIndex.textChanged.connect(self.reinitFigure)
        self.timeSelection.refIndex.textChanged.connect(self.reinitFigure)

        self.btnEvolution = QPushButton('BSS evolution', icon=self.style().standardIcon(QStyle.SP_DialogApplyButton))
        self.btnEvolution.setFixedSize(105, 50)

        self.btnCompute = QPushButton('Compute', icon=self.style().standardIcon(QStyle.SP_DialogApplyButton))
        self.btnCompute.setFixedSize(105, 50)
        self.resultTextBox = QPlainTextEdit()

        self.btnCompute.clicked.connect(self.btnComputeEvent)
        self.btnEvolution.clicked.connect(self.btnEvolutionEvent)

        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(10, 10))
        mainLayout.addWidget(self.timeSelection)
        mainLayout.addWidget(self.initSelection)
        mainLayout.addItem(QSpacerItem(10, 10))
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.btnEvolution)
        hlayout.addWidget(self.btnCompute)
        hlayout.setAlignment(self.btnEvolution, Qt.AlignTop)
        hlayout.setAlignment(self.btnCompute, Qt.AlignTop)
        hlayout.setAlignment(Qt.AlignHCenter)
        vlayout = QVBoxLayout()
        vlayout.addWidget(self.resultTextBox)
        hlayout.addItem(QSpacerItem(10, 1))
        hlayout.addLayout(vlayout)
        mainLayout.addLayout(hlayout)
        self.setLayout(mainLayout)

        self.template = '===\nComparison between Ref (frame {}) and Test (frame {})\n' \
                        'with respect to Init (frame {})\n===\n' \
                        'BSS\t{:<30}\n'

    def add_reference(self):
        self.timeSelection.initRef(self.input.ref_data.header.nb_frames)

    def add_test(self):
        self.timeSelection.initTest(self.input.test_data.header.nb_frames)
        self.initSelection.initRef(self.input.test_data.header.nb_frames)

    def reset(self):
        self.timeSelection.clearText()
        self.resultTextBox.clear()
        self.has_figure = False
        self.plotViewer.defaultPlot()
        self.plotViewer.current_title = 'Evolution of BSS'
        self.plotViewer.current_ylabel = 'BSS'
        self.plotViewer.current_xlabel = 'Time (second)'

    def reinitFigure(self):
        self.has_figure = False

    def btnEvolutionEvent(self):
        if not self.has_figure:
            all_bss = []
            ref_time = int(self.timeSelection.refIndex.text()) - 1

            init_time = int(self.initSelection.refIndex.text()) - 1
            selected_variable = self.input.varBox.currentText().split('(')[0][:-1]

            try:
                with Serafin.Read(self.input.ref_data.filename, self.input.ref_data.language) as input_stream:
                    input_stream.header = self.input.ref_data.header
                    input_stream.time = self.input.ref_data.time
                    ref_values = input_stream.read_var_in_frame(ref_time, selected_variable)

                with Serafin.Read(self.input.test_data.filename, self.input.test_data.language) as input_stream:
                    input_stream.header = self.input.test_data.header
                    input_stream.time = self.input.test_data.time
                    init_values = input_stream.read_var_in_frame(init_time, selected_variable)
                    ref_volume = self.input.ref_mesh.quadratic_volume(ref_values - init_values)

                    for index in range(len(self.input.test_data.time)):
                        test_values = input_stream.read_var_in_frame(index, selected_variable)

                        test_volume = self.input.ref_mesh.quadratic_volume(test_values - ref_values)
                        if test_volume == 0 and ref_volume == 0:
                            bss = 1
                        else:
                            with np.errstate(divide='ignore'):
                                bss = 1 - test_volume / ref_volume
                        all_bss.append(bss)
            except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e:
                QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok)
                return

            self.plotViewer.plot(self.input.test_data.time, all_bss)
        self.plotViewer.show()

    def btnComputeEvent(self):
        ref_time = int(self.timeSelection.refIndex.text()) - 1
        test_time = int(self.timeSelection.testIndex.text()) - 1
        init_time = int(self.initSelection.refIndex.text()) - 1
        selected_variable = self.input.varBox.currentText().split('(')[0][:-1]

        try:
            with Serafin.Read(self.input.ref_data.filename, self.input.ref_data.language) as input_stream:
                input_stream.header = self.input.ref_data.header
                input_stream.time = self.input.ref_data.time
                ref_values = input_stream.read_var_in_frame(ref_time, selected_variable)

            with Serafin.Read(self.input.test_data.filename, self.input.test_data.language) as input_stream:
                input_stream.header = self.input.test_data.header
                input_stream.time = self.input.test_data.time
                test_values = input_stream.read_var_in_frame(test_time, selected_variable)
                init_values = input_stream.read_var_in_frame(init_time, selected_variable)
        except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e:
            QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok)
            return

        test_volume = self.input.ref_mesh.quadratic_volume(test_values - ref_values)
        ref_volume = self.input.ref_mesh.quadratic_volume(ref_values - init_values)
        if test_volume == 0 and ref_volume == 0:
            bss = 1
        else:
            with np.errstate(divide='ignore'):
                bss = 1 - test_volume / ref_volume
        self.resultTextBox.appendPlainText(self.template.format(ref_time+1, test_time+1, init_time+1, bss))
Example #30
0
class Form(QWidget):
    def __init__(self, title=''):
        super().__init__()
        self.title = title
        self.initUI()

    def initUI(self):
        # Layouts
        self.main_layout = QVBoxLayout()
        self.h_layout = QHBoxLayout()
        self.form = QFormLayout()
        # Widgets
        font = QFont()
        font.setBold(True)
        font.setPointSize(12)
        font_o = QFont()
        font_o.setBold(True)
        font_o.setPointSize(10)
        self.name = QLabel(self.title)
        self.name.setFont(font)
        self.output = QPlainTextEdit()
        self.output.setReadOnly(True)
        self.output.setFont(font_o)
        self.run = QPushButton('Run Algorithm')
        self.clear = QPushButton('Clear')
        self.run.setMinimumSize(100, 30)
        self.clear.setMinimumSize(100, 30)
        self.generate_fields()
        # Setup main layout
        self.main_layout.addWidget(self.name)
        self.main_layout.addLayout(self.form)
        self.main_layout.addWidget(self.output)
        self.main_layout.addLayout(self.h_layout)
        # Setup h layout
        self.h_layout.addStretch()
        self.h_layout.addWidget(self.clear)
        self.h_layout.addWidget(self.run)
        self.setLayout(self.main_layout)
        # Conecting button.
        self.run.clicked.connect(self.run_algorithm)
        self.clear.clicked.connect(self.clear_output)
        self.show()

    def generate_fields(self):
        raise NotImplementedError

    def run_algorithm(self):
        raise NotImplementedError

    def clear_output(self):
        self.output.clear()

    def print_results(self, values, t_time):
        self.output.appendPlainText('Results:')
        self.print_values(values)
        self.output.appendPlainText('Time: {}'.format(t_time))
        self.output.appendPlainText('')

    def print_results_p(self, bests, t_time):
        self.output.appendPlainText('Results:')
        for i, best in bests.items():
            self.output.appendPlainText('Thread: {}'.format(i))
            self.print_values(best.get_values())
        self.output.appendPlainText('Time: {}'.format(t_time))
        self.output.appendPlainText('')

    def print_values(self, values):
        self.output.appendPlainText('R: {}'.format(values[0]))
        self.output.appendPlainText('L: {}'.format(values[1]))
        self.output.appendPlainText('J: {}'.format(values[2]))
        self.output.appendPlainText('Lam: {}'.format(values[3]))
Example #31
0
class Ui_ProjectorEditForm(object):
    """
    The :class:`~openlp.core.lib.ui.projector.editform.Ui_ProjectorEditForm` class defines
    the user interface for the ProjectorEditForm dialog.
    """
    def setupUi(self, edit_projector_dialog):
        """
        Create the interface layout.
        """
        edit_projector_dialog.setObjectName('edit_projector_dialog')
        edit_projector_dialog.setWindowIcon(
            build_icon(u':/icon/openlp-logo-32x32.png'))
        edit_projector_dialog.setMinimumWidth(400)
        edit_projector_dialog.setModal(True)
        # Define the basic layout
        self.dialog_layout = QGridLayout(edit_projector_dialog)
        self.dialog_layout.setObjectName('dialog_layout')
        self.dialog_layout.setSpacing(8)
        self.dialog_layout.setContentsMargins(8, 8, 8, 8)
        # IP Address
        self.ip_label = QLabel(edit_projector_dialog)
        self.ip_label.setObjectName('projector_edit_ip_label')
        self.ip_text = QLineEdit(edit_projector_dialog)
        self.ip_text.setObjectName('projector_edit_ip_text')
        self.dialog_layout.addWidget(self.ip_label, 0, 0)
        self.dialog_layout.addWidget(self.ip_text, 0, 1)
        # Port number
        self.port_label = QLabel(edit_projector_dialog)
        self.port_label.setObjectName('projector_edit_ip_label')
        self.port_text = QLineEdit(edit_projector_dialog)
        self.port_text.setObjectName('projector_edit_port_text')
        self.dialog_layout.addWidget(self.port_label, 1, 0)
        self.dialog_layout.addWidget(self.port_text, 1, 1)
        # PIN
        self.pin_label = QLabel(edit_projector_dialog)
        self.pin_label.setObjectName('projector_edit_pin_label')
        self.pin_text = QLineEdit(edit_projector_dialog)
        self.pin_label.setObjectName('projector_edit_pin_text')
        self.dialog_layout.addWidget(self.pin_label, 2, 0)
        self.dialog_layout.addWidget(self.pin_text, 2, 1)
        # Name
        self.name_label = QLabel(edit_projector_dialog)
        self.name_label.setObjectName('projector_edit_name_label')
        self.name_text = QLineEdit(edit_projector_dialog)
        self.name_text.setObjectName('projector_edit_name_text')
        self.dialog_layout.addWidget(self.name_label, 3, 0)
        self.dialog_layout.addWidget(self.name_text, 3, 1)
        # Location
        self.location_label = QLabel(edit_projector_dialog)
        self.location_label.setObjectName('projector_edit_location_label')
        self.location_text = QLineEdit(edit_projector_dialog)
        self.location_text.setObjectName('projector_edit_location_text')
        self.dialog_layout.addWidget(self.location_label, 4, 0)
        self.dialog_layout.addWidget(self.location_text, 4, 1)
        # Notes
        self.notes_label = QLabel(edit_projector_dialog)
        self.notes_label.setObjectName('projector_edit_notes_label')
        self.notes_text = QPlainTextEdit(edit_projector_dialog)
        self.notes_text.setObjectName('projector_edit_notes_text')
        self.dialog_layout.addWidget(self.notes_label,
                                     5,
                                     0,
                                     alignment=QtCore.Qt.AlignTop)
        self.dialog_layout.addWidget(self.notes_text, 5, 1)
        # Time for the buttons
        self.button_box = QDialogButtonBox(QDialogButtonBox.Help
                                           | QDialogButtonBox.Save
                                           | QDialogButtonBox.Cancel)
        self.dialog_layout.addWidget(self.button_box, 8, 0, 1, 2)

    def retranslateUi(self, edit_projector_dialog):
        if self.new_projector:
            title = translate('OpenLP.ProjectorEditForm', 'Add New Projector')
            self.projector.port = PJLINK_PORT
        else:
            title = translate('OpenLP.ProjectorEditForm', 'Edit Projector')
        edit_projector_dialog.setWindowTitle(title)
        self.ip_label.setText(
            translate('OpenLP.ProjectorEditForm', 'IP Address'))
        self.ip_text.setText(self.projector.ip)
        self.ip_text.setFocus()
        self.port_label.setText(
            translate('OpenLP.ProjectorEditForm', 'Port Number'))
        self.port_text.setText(str(self.projector.port))
        self.pin_label.setText(translate('OpenLP.ProjectorEditForm', 'PIN'))
        self.pin_text.setText(self.projector.pin)
        self.name_label.setText(translate('OpenLP.ProjectorEditForm', 'Name'))
        self.name_text.setText(self.projector.name)
        self.location_label.setText(
            translate('OpenLP.ProjectorEditForm', 'Location'))
        self.location_text.setText(self.projector.location)
        self.notes_label.setText(translate('OpenLP.ProjectorEditForm',
                                           'Notes'))
        self.notes_text.clear()
        self.notes_text.insertPlainText(self.projector.notes)
Example #32
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.running = False
        self.setWindowTitle('PySwicher v{}'.format(VERSION))

        # Logging config
        self.log_textbox = QPlainTextEditLogger(self)
        logging.getLogger().addHandler(self.log_textbox)
        self.log_textbox.setFormatter(logging.Formatter('[%(asctime)s][%(levelname)s]:    %(message)s'))
        self.log_textbox.setLevel(self.get_numeric_loglevel(options['log_level']))
        self.log_to_file = False

        # System tray configuration
        self.tray_menu = QMenu(self)
        self.systemTrayIcon = QSystemTrayIcon()
        self.systemTrayIcon.setVisible(False)
        self.systemTrayIcon.setIcon(QtGui.QIcon('C:\\Users\\Admin\\Pictures\\tray_stop.jpg'))
        self.systemTrayIcon.activated.connect(self.sys_tray)
        self.exit_action = self.tray_menu.addAction('Exit')
        self.exit_action.triggered.connect(self.exit_app)
        self.systemTrayIcon.setContextMenu(self.tray_menu)
        self.click_tray_timer = QtCore.QTimer(self)  # Fix for systemtray click trigger
        self.click_tray_timer.setSingleShot(True)
        self.click_tray_timer.timeout.connect(self.click_timeout)

        self.main_window_ui()
        self.starter()

    def set_log_to_file(self, state):
        logger = logging.getLogger(__name__)
        file = logging.FileHandler(HOME + '\\switcher.log')
        if state == QtCore.Qt.Checked:
            self.log_to_file = True
            file.setFormatter(
                logging.Formatter('%(filename)s[LINE:%(lineno)d]# %(levelname)-8s [%(asctime)s]  %(message)s'))
            file.setLevel(self.get_numeric_loglevel(options['log_level']))
            logger.addHandler(file)
        else:
            if 'file' in logger.handlers:
                logger.removeHandler(file)
            self.log_to_file = False

    def starter(self):
        if not self.running:
            self.running = True
            self.start_btn.setText('Stop switcher')
            self.systemTrayIcon.setIcon(QtGui.QIcon('C:\\Users\\Admin\\Pictures\\tray_stop.jpg'))
            start_app()
        elif self.running:
            self.running = False
            self.start_btn.setText('Start switcher')
            self.systemTrayIcon.setIcon(QtGui.QIcon('C:\\Users\\Admin\\Pictures\\tray_start.jpg'))
            stop_app()
        return

    def main_window_ui(self):
        grid = QGridLayout(self)
        self.setLayout(grid)
        grid.setSpacing(5)

        # Here goes options layout
        self.topleft = QFrame(self)
        self.topleft.setFrameShape(QFrame.StyledPanel)
        self.topleft_grid = QGridLayout(self)
        self.topleft.setLayout(self.topleft_grid)

        self.switch_comb_label = QLabel('Switch combination:')
        self.switch_comb_text = QLineEdit()
        self.switch_comb_text.setText(options['switch_combination'])

        self.hotkey_label = QLabel('Hotkey:')
        self.hotkey_comb_text = QLineEdit()
        self.hotkey_comb_text.setText(options['hotkey'])

        self.topleft_grid.addWidget(self.switch_comb_label, 0, 0)
        self.topleft_grid.addWidget(self.switch_comb_text, 1, 0)
        self.topleft_grid.addWidget(self.hotkey_label, 2, 0)
        self.topleft_grid.addWidget(self.hotkey_comb_text, 3, 0)

        grid.addWidget(self.topleft, 0, 0)

        self.topright = QFrame(self)
        self.topright.setFrameShape(QFrame.StyledPanel)
        self.topright_grid = QGridLayout(self)
        self.topright.setLayout(self.topright_grid)

        self.info_label = QLabel('===INFO===')
        self.info_label.setAlignment(QtCore.Qt.AlignHCenter)

        self.info_author = QLabel('Author: Kurashov Sergey')
        self.info_author.setAlignment(QtCore.Qt.AlignHCenter)

        self.info_contacts = QLabel('Contacts: [email protected]')
        self.info_contacts.setAlignment(QtCore.Qt.AlignHCenter)

        self.info_sourcecode = QLabel('<a href="https://github.com/shimielder/win_switcher">Sourcecode on GitHub</a>')
        self.info_sourcecode.setAlignment(QtCore.Qt.AlignHCenter)
        self.info_sourcecode.setOpenExternalLinks(True)

        self.topright_grid.addWidget(self.info_label, 0, 0)
        self.topright_grid.addWidget(self.info_author, 1, 0)
        self.topright_grid.addWidget(self.info_contacts, 2, 0)
        self.topright_grid.addWidget(self.info_sourcecode, 3, 0)

        grid.addWidget(self.topright, 0, 1)

        self.middle = QFrame(self)
        self.middle.setFrameShape(QFrame.StyledPanel)
        self.middle_grid = QGridLayout(self)
        self.middle.setLayout(self.middle_grid)

        self.dictionsries_label = QLabel('Dictionaries to switch:')
        self.dict_one = QPlainTextEdit()
        self.dict_one.clear()
        self.dict_one.appendPlainText(options['layouts'][0])
        self.dict_two = QPlainTextEdit()
        self.dict_two.clear()
        self.dict_two.appendPlainText(options['layouts'][1])

        self.middle_grid.addWidget(self.dictionsries_label, 0, 0, 1, 4)
        self.middle_grid.addWidget(self.dict_one, 1, 0, 1, 4)
        self.middle_grid.addWidget(self.dict_two, 2, 0, 1, 4)
        grid.addWidget(self.middle, 1, 0, 1, 2)

        self.bottom = QFrame(self)
        self.bottom.setFrameShape(QFrame.StyledPanel)
        self.bottom_grid = QGridLayout(self)
        self.bottom.setLayout(self.bottom_grid)

        self.loglevel_label = QLabel('Logging level:')
        self.loglevel_dropmenu = QComboBox(self)
        self.loglevel_dropmenu.addItems(LOGGING_LEVELS)
        self.loglevel_dropmenu.setCurrentIndex(LOGGING_LEVELS.index((options['log_level'].upper())))
        self.loglevel_dropmenu.activated[str].connect(self.set_logginglevel)

        # self.log_to_file_label = QLabel('Check to save logs to file')
        self.log_to_file_chk = QCheckBox('Check to save logs to file')
        self.log_to_file_chk.stateChanged.connect(self.set_log_to_file)

        self.logging_output_label = QLabel('Logging output:')
        self.logging_output_label.setAlignment(QtCore.Qt.AlignHCenter)

        self.bottom_grid.addWidget(self.loglevel_label, 0, 0)
        self.bottom_grid.addWidget(self.loglevel_dropmenu, 0, 1)
        self.bottom_grid.addWidget(self.log_to_file_chk, 0, 3, 1, 1)
        self.bottom_grid.addWidget(self.logging_output_label, 1, 0, 1, 4)
        self.bottom_grid.addWidget(self.log_textbox.widget, 2, 0, 2, 4)
        grid.addWidget(self.bottom, 2, 0, 1, 2)

        self.bottom_buttons = QFrame(self)
        # self.bottom_buttons.setFrameShape(QFrame.StyledPanel)
        self.bottom_buttons_grid = QGridLayout(self)
        self.bottom_buttons.setLayout(self.bottom_buttons_grid)

        self.start_btn = QPushButton('Start switcher')
        self.start_btn.clicked.connect(self.starter)
        self.apply_btn = QPushButton('Apply changes')
        self.apply_btn.clicked.connect(self.apply)
        self.exit_btn = QPushButton('Exit app')
        self.exit_btn.clicked.connect(self.exit_app)

        self.bottom_buttons_grid.addWidget(self.start_btn, 0, 0)
        self.bottom_buttons_grid.addWidget(self.apply_btn, 0, 1)
        self.bottom_buttons_grid.addWidget(self.exit_btn, 0, 2)
        grid.addWidget(self.bottom_buttons, 3, 0, 1, 2)

        self.resize(480, 320)
        self.show()

    def get_numeric_loglevel(self, loglevel):
        numeric_level = getattr(logging, loglevel.upper(), None)
        if not isinstance(numeric_level, int):
            numeric_level = 0
        return numeric_level

    def set_logginglevel(self, loglevel):
        return self.log_textbox.setLevel(self.get_numeric_loglevel(loglevel))

    @QtCore.pyqtSlot(QSystemTrayIcon.ActivationReason)
    def sys_tray(self, reason):
        """
        По-умолчанию, trigger срабатывает всегда. Для обхода этого
        я повесил таймер на событие.
        Взято отсюда:
        https://riverbankcomputing.com/pipermail/pyqt/2010-November/028394.html
        """
        if reason == QSystemTrayIcon.Trigger:
            self.click_tray_timer.start(QApplication.doubleClickInterval())
        elif reason == QSystemTrayIcon.DoubleClick:
            self.click_tray_timer.stop()
            if self.isHidden():
                self.showNormal()
                self.systemTrayIcon.setVisible(False)

    def click_timeout(self):
        self.starter()

    def apply(self):
        self.starter()
        options['layouts'] = []
        options['layouts'].append(self.dict_one.toPlainText())
        options['layouts'].append(self.dict_two.toPlainText())
        options['log_level'] = LOGGING_LEVELS[self.loglevel_dropmenu.currentIndex()]
        self.set_logginglevel(options['log_level'])
        options['switch_combination'] = self.switch_comb_text.text()
        options['hotkey'] = self.hotkey_comb_text.text()
        logging.debug('Options from GUI: {}'.format(options))
        save_to(options)
        self.starter()
        return options

    def exit_app(self):
        if self.running:
            self.starter()
        self.systemTrayIcon.setVisible(False)
        self.destroy()

    def closeEvent(self, event):
        self.exit_app()

    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.WindowStateChange:
            if self.windowState() & QtCore.Qt.WindowMinimized:
                event.ignore()
                self.hide()
                self.systemTrayIcon.setVisible(True)
                self.systemTrayIcon.showMessage('', 'Running in the background.')
        super(MainWindow, self).changeEvent(event)
class MultipleLinearRegression(QMainWindow):
    #::----------------------
    # Implementation of Multiple Linear regression using the bike share dataset
    # the methods in this class are
    #       _init_ : initialize the class
    #       initUi : creates the canvas and all the elements in the canvas
    #       update : populates the elements of the canvas base on the parametes
    #               chosen by the user
    #::----------------------

    send_fig = pyqtSignal(str)

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

        self.Title ="Multiple Linear Regression"
        self.initUi()

    def initUi(self):
        #::-----------------------------------------------------------------
        #  Create the canvas and all the element to create a dashboard with
        #  all the necessary elements to present the results from the algorithm
        #  The canvas is divided using a  grid layout to facilitate the drawing
        #  of the elements
        #::-----------------------------------------------------------------

        self.setWindowTitle(self.Title)
        self.setStyleSheet(font_size_window)

        self.main_widget = QWidget(self)

        self.layout = QGridLayout(self.main_widget)

        self.groupBox1 = QGroupBox('Independent Variables')
        self.groupBox1Layout = QGridLayout()
        self.groupBox1.setLayout(self.groupBox1Layout)

        # Create check boxes for each feature
        self.feature0 = QCheckBox(features_list[0], self)
        self.feature1 = QCheckBox(features_list[1], self)
        self.feature2 = QCheckBox(features_list[2], self)
        self.feature3 = QCheckBox(features_list[3], self)
        self.feature4 = QCheckBox(features_list[4], self)
        self.feature5 = QCheckBox(features_list[5], self)
        self.feature6 = QCheckBox(features_list[6], self)
        self.feature7 = QCheckBox(features_list[7], self)
        self.feature8 = QCheckBox(features_list[8], self)
        self.feature9 = QCheckBox(features_list[9], self)
        self.feature10 = QCheckBox(features_list[10], self)
        self.feature0.setChecked(True)
        self.feature1.setChecked(False)
        self.feature2.setChecked(True)
        self.feature3.setChecked(True)
        self.feature4.setChecked(True)
        self.feature5.setChecked(True)
        self.feature6.setChecked(True)
        self.feature7.setChecked(True)
        self.feature8.setChecked(True)
        self.feature9.setChecked(True)
        self.feature10.setChecked(True)

        self.btnExecute = QPushButton("Run Regression")
        self.btnExecute.clicked.connect(self.update)

        self.groupBox1Layout.addWidget(self.feature0, 0, 0)
        self.groupBox1Layout.addWidget(self.feature1, 0, 1)
        self.groupBox1Layout.addWidget(self.feature2, 0, 2)
        self.groupBox1Layout.addWidget(self.feature3, 0, 3)
        self.groupBox1Layout.addWidget(self.feature4, 1, 0)
        self.groupBox1Layout.addWidget(self.feature5, 1, 1)
        self.groupBox1Layout.addWidget(self.feature6, 1, 2)
        self.groupBox1Layout.addWidget(self.feature7, 1, 3)
        self.groupBox1Layout.addWidget(self.feature8, 2, 0)
        self.groupBox1Layout.addWidget(self.feature9, 2, 1)
        self.groupBox1Layout.addWidget(self.feature10, 2, 2)
        self.groupBox1Layout.addWidget(self.btnExecute, 3, 1)

        self.groupBox3 = QGroupBox('')
        self.groupBox3Layout = QGridLayout()
        self.groupBox3.setLayout(self.groupBox3Layout)

        self.groupBox4 = QGroupBox('Parameters of the Model')
        self.groupBox4Layout = QGridLayout()
        self.groupBox4.setLayout(self.groupBox4Layout)

        self.groupBox2 = QGroupBox('Results from the model')
        self.groupBox2Layout = QVBoxLayout()
        self.groupBox2.setLayout(self.groupBox2Layout)

        self.lblInt = QLabel('Intercept:')
        self.txtInt = QLineEdit()
        self.lblR2 = QLabel('R2:')
        self.txtR2 = QLineEdit()
        self.lblMSE = QLabel('Mean Squared Error:')
        self.txtMSE = QLineEdit()
        self.lblRMSE = QLabel('RMSE:')
        self.txtRMSE = QLineEdit()


        self.lblParam = QLabel("Coefficients:")
        self.lblParam.adjustSize()
        self.txtParam = QPlainTextEdit()

        self.groupBox2Layout.addWidget(self.lblInt)
        self.groupBox2Layout.addWidget(self.txtInt)
        self.groupBox2Layout.addWidget(self.lblR2)
        self.groupBox2Layout.addWidget(self.txtR2)
        self.groupBox2Layout.addWidget(self.lblMSE)
        self.groupBox2Layout.addWidget(self.txtMSE)
        self.groupBox2Layout.addWidget(self.lblRMSE)
        self.groupBox2Layout.addWidget(self.txtRMSE)

        self.groupBox4Layout.addWidget(self.lblParam)
        self.groupBox4Layout.addWidget(self.txtParam)

        self.layout.addWidget(self.groupBox1, 0, 0)
        self.layout.addWidget(self.groupBox2, 1, 0)
        self.layout.addWidget(self.groupBox3, 0, 1)
        self.layout.addWidget(self.groupBox4, 1, 1)

        #::--------------------------------------
        # Graphic 1 : Residuals
        #::--------------------------------------

        self.fig = Figure()
        self.ax1 = self.fig.add_subplot(111)
        self.axes = [self.ax1]
        self.canvas = FigureCanvas(self.fig)

        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.canvas.updateGeometry()

        self.groupBoxG3 = QGroupBox('Residuals Plot')
        self.groupBoxG3Layout = QVBoxLayout()
        self.groupBoxG3.setLayout(self.groupBoxG3Layout)

        self.groupBoxG3Layout.addWidget(self.canvas)

        self.layout.addWidget(self.groupBoxG3,0,1)

        self.setCentralWidget(self.main_widget)
        self.resize(1100, 700)
        self.show()

    def update(self):
    #::------------------------------------------------------------
    # Populates the elements in the canvas using the values
    # chosen as parameters for the multiple linear regression
    #::------------------------------------------------------------
        self.ax1.clear()
        self.txtParam.clear()

        self.Y = london_bikes['count']
        self.X = pd.DataFrame()
        if self.feature0.isChecked():
            self.X[features_list[0]] = london_bikes[features_list[0]]
        if self.feature1.isChecked():
            self.X[features_list[1]] = london_bikes[features_list[1]]
        if self.feature2.isChecked():
            self.X[features_list[2]] = london_bikes[features_list[2]]
        if self.feature3.isChecked():
            self.X[features_list[3]] = london_bikes[features_list[3]]
        if self.feature4.isChecked():
            self.X[features_list[4]] = london_bikes[features_list[4]]
        if self.feature5.isChecked():
            self.X[features_list[5]] = london_bikes[features_list[5]]
        if self.feature6.isChecked():
            self.X[features_list[6]] = london_bikes[features_list[6]]
        if self.feature7.isChecked():
            self.X[features_list[7]] = london_bikes[features_list[7]]
        if self.feature8.isChecked():
            self.X[features_list[8]] = london_bikes[features_list[8]]
        if self.feature9.isChecked():
            self.X[features_list[9]] = london_bikes[features_list[9]]
        if self.feature10.isChecked():
            self.X[features_list[10]] = london_bikes[features_list[10]]

        # splitting X and y into training and testing sets
        self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(self.X, self.Y,
                                                                                test_size=0.4,
                                                                                random_state=1)

        # create linear regression object
        self.reg = linear_model.LinearRegression()

        # train the model using the training sets
        self.results = self.reg.fit(self.X_train, self.y_train)
        self.y_pred = self.reg.predict(self.X_test)


        # intercept
        self.Int = self.reg.intercept_

        # regression coefficients
        self.coef =  self.reg.coef_
        # zip with features
        self.parameters = zip(self.X.columns, self.coef)

        # variance score: 1 means perfect prediction
        self.variance = self.reg.score(self.X_test, self.y_test)

        # R2 and Mean Squared Error
        self.R2 = r2_score(self.y_test, self.y_pred)  # Priniting R2 Score
        self.MSE = mean_squared_error(self.y_test, self.y_pred)

        # RMSE
        self.RMSE = np.sqrt(self.MSE)


        self.txtInt.setText(str(self.Int))
        self.txtR2.setText(str(self.R2))
        self.txtMSE.setText(str(self.MSE))
        self.txtRMSE.setText(str(self.RMSE))
        self.txtParam.appendPlainText(str(list(self.parameters)))



        ### Plot residuals
        self.ax1.scatter(self.reg.predict(self.X_train), self.reg.predict(self.X_train) - self.y_train,
            color="green", s=10, label='Train data')
        ## plotting residual errors in test data
        self.ax1.scatter(self.reg.predict(self.X_test), self.reg.predict(self.X_test) - self.y_test,
                color="blue", s=10, label='Test data')
        ## plotting line for zero residual error
        self.ax1.hlines(y=0, xmin=0, xmax=10, linewidth=2)
        ## plotting line for zero residual error
        self.ax1.hlines(y=0, xmin=0, xmax=10, linewidth=2)
        ## plotting legend
        self.ax1.legend(loc='upper right')


        self.fig.tight_layout()
        self.fig.canvas.draw_idle()
Example #34
0
class PreparePanel(QWidget, TaskManager):

    signal_status = pyqtSignal(object, object)
    signal_password_response = pyqtSignal(str, bool)

    def __init__(self, context: ApplicationContext, manager: SoftwareManager,
                 screen_size: QSize, i18n: I18n, manage_window: QWidget):
        super(PreparePanel,
              self).__init__(flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint)
        self.i18n = i18n
        self.context = context
        self.manage_window = manage_window
        self.setWindowTitle('{} ({})'.format(
            __app_name__, self.i18n['prepare_panel.title.start'].lower()))
        self.setMinimumWidth(screen_size.width() * 0.5)
        self.setMinimumHeight(screen_size.height() * 0.35)
        self.setMaximumHeight(screen_size.height() * 0.95)
        self.setLayout(QVBoxLayout())
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
        self.manager = manager
        self.tasks = {}
        self.output = {}
        self.ntasks = 0
        self.ftasks = 0
        self.self_close = False

        self.prepare_thread = Prepare(self.context, manager, self.i18n)
        self.prepare_thread.signal_register.connect(self.register_task)
        self.prepare_thread.signal_update.connect(self.update_progress)
        self.prepare_thread.signal_finished.connect(self.finish_task)
        self.prepare_thread.signal_started.connect(self.start)
        self.prepare_thread.signal_ask_password.connect(self.ask_root_password)
        self.prepare_thread.signal_output.connect(self.update_output)
        self.signal_password_response.connect(
            self.prepare_thread.set_password_reply)

        self.check_thread = CheckFinished()
        self.signal_status.connect(self.check_thread.update)
        self.check_thread.signal_finished.connect(self.finish)

        self.skip_thread = EnableSkip()
        self.skip_thread.signal_timeout.connect(self._enable_skip_button)

        self.progress_thread = AnimateProgress()
        self.progress_thread.signal_change.connect(self._change_progress)

        self.label_top = QLabel()
        self.label_top.setCursor(QCursor(Qt.WaitCursor))
        self.label_top.setText("{}...".format(
            self.i18n['prepare_panel.title.start'].capitalize()))
        self.label_top.setAlignment(Qt.AlignHCenter)
        self.label_top.setStyleSheet(
            "QLabel { font-size: 14px; font-weight: bold; }")
        self.layout().addWidget(self.label_top)
        self.layout().addWidget(QLabel())

        self.table = QTableWidget()
        self.table.setCursor(QCursor(Qt.WaitCursor))
        self.table.setStyleSheet(
            "QTableWidget { background-color: transparent; }")
        self.table.setFocusPolicy(Qt.NoFocus)
        self.table.setShowGrid(False)
        self.table.verticalHeader().setVisible(False)
        self.table.horizontalHeader().setVisible(False)
        self.table.horizontalHeader().setSizePolicy(
            QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(['' for _ in range(4)])
        self.layout().addWidget(self.table)

        self.textarea_output = QPlainTextEdit(self)
        self.textarea_output.resize(self.table.size())
        self.textarea_output.setStyleSheet("background: black; color: white;")
        self.layout().addWidget(self.textarea_output)
        self.textarea_output.setVisible(False)
        self.textarea_output.setReadOnly(True)
        self.textarea_output.setMaximumHeight(100)
        self.current_output_task = None

        self.bottom_widget = QWidget()
        self.bottom_widget.setLayout(QHBoxLayout())
        self.bottom_widget.layout().addStretch()
        bt_hide_output = QPushButton(self.i18n['prepare.bt_hide_details'])
        bt_hide_output.setStyleSheet(
            'QPushButton { text-decoration: underline; border: 0px; background: none } '
        )
        bt_hide_output.clicked.connect(self.hide_output)
        bt_hide_output.setCursor(QCursor(Qt.PointingHandCursor))
        self.bottom_widget.layout().addWidget(bt_hide_output)
        self.bottom_widget.layout().addStretch()
        self.layout().addWidget(self.bottom_widget)
        self.bottom_widget.setVisible(False)

        self.bt_bar = QToolBar()
        self.bt_close = QPushButton(self.i18n['close'].capitalize())
        self.bt_close.setCursor(QCursor(Qt.PointingHandCursor))
        self.bt_close.clicked.connect(self.close)
        self.bt_close.setVisible(False)
        self.ref_bt_close = self.bt_bar.addWidget(self.bt_close)

        self.bt_bar.addWidget(new_spacer())
        self.progress_bar = QProgressBar()
        self.progress_bar.setStyleSheet(styles.PROGRESS_BAR)
        self.progress_bar.setMaximumHeight(10 if QApplication.instance().style(
        ).objectName().lower() == 'windows' else 4)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setVisible(False)
        self.progress_bar.setCursor(QCursor(Qt.WaitCursor))
        self.ref_progress_bar = self.bt_bar.addWidget(self.progress_bar)
        self.bt_bar.addWidget(new_spacer())

        self.bt_skip = QPushButton(
            self.i18n['prepare_panel.bt_skip.label'].capitalize())
        self.bt_skip.clicked.connect(self.finish)
        self.bt_skip.setEnabled(False)
        self.bt_skip.setCursor(QCursor(Qt.WaitCursor))
        self.bt_bar.addWidget(self.bt_skip)

        self.layout().addWidget(self.bt_bar)

    def hide_output(self):
        self.current_output_task = None
        self.textarea_output.setVisible(False)
        self.textarea_output.clear()
        self.bottom_widget.setVisible(False)
        self._resize_columns()
        self.setFocus(Qt.NoFocusReason)

        if not self.bt_bar.isVisible():
            self.bt_bar.setVisible(True)

    def ask_root_password(self):
        root_pwd, ok = root.ask_root_password(self.context, self.i18n)
        self.signal_password_response.emit(root_pwd, ok)

    def _enable_skip_button(self):
        self.bt_skip.setEnabled(True)
        self.bt_skip.setCursor(QCursor(Qt.PointingHandCursor))

    def _change_progress(self, value: int):
        self.progress_bar.setValue(value)

    def get_table_width(self) -> int:
        return reduce(operator.add, [
            self.table.columnWidth(i) for i in range(self.table.columnCount())
        ])

    def _resize_columns(self):
        header_horizontal = self.table.horizontalHeader()
        for i in range(self.table.columnCount()):
            header_horizontal.setSectionResizeMode(
                i, QHeaderView.ResizeToContents)

        self.resize(self.get_table_width() * 1.05, self.sizeHint().height())

    def show(self):
        super(PreparePanel, self).show()
        self.prepare_thread.start()
        centralize(self)

    def start(self):
        self.ref_bt_close.setVisible(True)
        self.check_thread.start()
        self.skip_thread.start()

        self.ref_progress_bar.setVisible(True)
        self.progress_thread.start()

    def closeEvent(self, QCloseEvent):
        if not self.self_close:
            QCoreApplication.exit()

    def register_task(self, id_: str, label: str, icon_path: str):
        self.ntasks += 1
        self.table.setRowCount(self.ntasks)

        task_row = self.ntasks - 1

        icon_widget = QWidget()
        icon_widget.setLayout(QHBoxLayout())
        icon_widget.layout().setContentsMargins(10, 0, 10, 0)
        bt_icon = QToolButton()
        bt_icon.setCursor(QCursor(Qt.WaitCursor))
        bt_icon.setEnabled(False)
        bt_icon.setToolTip(self.i18n['prepare.bt_icon.no_output'])
        bt_icon.setFixedSize(QSize(24, 24))
        bt_icon.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)

        if icon_path:
            bt_icon.setIcon(QIcon(icon_path))

        def _show_output():
            lines = self.output[id_]

            if lines:
                self.current_output_task = id_
                self.textarea_output.clear()
                self.textarea_output.setVisible(True)

                for l in lines:
                    self.textarea_output.appendPlainText(l)

                self.bottom_widget.setVisible(True)

            self.setFocus(Qt.NoFocusReason)

            if self.bt_bar.isVisible():
                self.bt_bar.setVisible(False)

        bt_icon.clicked.connect(_show_output)
        icon_widget.layout().addWidget(bt_icon)

        self.table.setCellWidget(task_row, 0, icon_widget)

        lb_status = QLabel(label)
        lb_status.setCursor(Qt.WaitCursor)
        lb_status.setMinimumWidth(50)
        lb_status.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
        lb_status.setStyleSheet("QLabel { font-weight: bold; }")
        self.table.setCellWidget(task_row, 1, lb_status)

        lb_sub = QLabel()
        lb_status.setCursor(Qt.WaitCursor)
        lb_sub.setContentsMargins(10, 0, 10, 0)
        lb_sub.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
        lb_sub.setMinimumWidth(50)
        self.table.setCellWidget(task_row, 2, lb_sub)

        lb_progress = QLabel('{0:.2f}'.format(0) + '%')
        lb_progress.setCursor(Qt.WaitCursor)
        lb_progress.setContentsMargins(10, 0, 10, 0)
        lb_progress.setStyleSheet("QLabel { font-weight: bold; }")
        lb_progress.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)

        self.table.setCellWidget(task_row, 3, lb_progress)

        self.tasks[id_] = {
            'bt_icon': bt_icon,
            'lb_status': lb_status,
            'lb_prog': lb_progress,
            'progress': 0,
            'lb_sub': lb_sub,
            'finished': False
        }

        self.signal_status.emit(self.ntasks, self.ftasks)

    def update_progress(self, task_id: str, progress: float, substatus: str):
        task = self.tasks[task_id]

        if progress != task['progress']:
            task['progress'] = progress
            task['lb_prog'].setText('{0:.2f}'.format(progress) + '%')

        if substatus:
            task['lb_sub'].setText('( {} )'.format(substatus))
        else:
            task['lb_sub'].setText('')

        self._resize_columns()

    def update_output(self, task_id: str, output: str):
        full_output = self.output.get(task_id)

        if full_output is None:
            full_output = []
            self.output[task_id] = full_output
            task = self.tasks[task_id]
            task['bt_icon'].setEnabled(True)
            task['bt_icon'].setCursor(QCursor(Qt.PointingHandCursor))
            task['bt_icon'].setToolTip(self.i18n['prepare.bt_icon.output'])

        full_output.append(output)

        if self.current_output_task == task_id:
            self.textarea_output.appendPlainText(output)

    def finish_task(self, task_id: str):
        task = self.tasks[task_id]
        task['lb_sub'].setText('')

        for key in ('lb_prog', 'lb_status'):
            task[key].setStyleSheet(
                'QLabel { color: %s; text-decoration: line-through; }' % GREEN)

        task['finished'] = True
        self._resize_columns()

        self.ftasks += 1
        self.signal_status.emit(self.ntasks, self.ftasks)

        if self.ntasks == self.ftasks:
            self.label_top.setText(self.i18n['ready'].capitalize())

    def finish(self):
        if self.isVisible():
            self.manage_window.begin_refresh_packages()
            self.manage_window.show()
            self.self_close = True
            self.close()