Ejemplo n.º 1
1
class SerialTerminalWidget(QWidget):
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        self.initUI()

    def initUI(self):
        self.bundle_dir = os.path.dirname(os.path.abspath(__file__))
        self.layout = QVBoxLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)

        self.cliTextEdit = QPlainTextEdit(
            "CLI mode, type 'exit' to return, or 'help'\n\n")
        self.cliTextEdit.setStyleSheet(
            "QPlainTextEdit {background-color:gray; color:white; min-height:590; max-height:600}"
        )
        self.cliInputLine = QLineEdit()
        self.cliInputLine.returnPressed.connect(self.newInputReceived)

        self.layout.addWidget(self.cliTextEdit)
        self.layout.addWidget(self.cliInputLine)
        self.layout.addStretch(1)

        # Set Main Layout of this page
        self.setLayout(self.layout)

    def newInputReceived(self):
        waitingText = self.cliInputLine.text()
        if len(waitingText) > 0:
            self.cliTextEdit.appendPlainText("$" + waitingText)
            self.cliInputLine.setText("")
Ejemplo n.º 2
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))
Ejemplo n.º 3
0
    def slot_edit_palette_data(self):
        dialog = QDialog(self)
        tabWidget = QTabWidget()
        dialog.setWindowTitle(i18n("Edit Palette Data"))
        dialog.setLayout(QVBoxLayout())
        dialog.layout().addWidget(tabWidget)
        paletteWidget = QWidget()
        paletteWidget.setLayout(QVBoxLayout())
        tabWidget.addTab(paletteWidget, i18n("Palette Data"))
        paletteName = QLineEdit()
        paletteName.setText(self.cmb_palettes.currentText())
        paletteWidget.layout().addWidget(paletteName)
        paletteColumns = QSpinBox()
        paletteColumns.setValue(self.currentPalette.columnCount())
        paletteWidget.layout().addWidget(paletteColumns)
        paletteComment = QPlainTextEdit()
        paletteComment.appendPlainText(self.currentPalette.comment())
        paletteWidget.layout().addWidget(paletteComment)
        buttons = QDialogButtonBox(QDialogButtonBox.Ok)
        dialog.layout().addWidget(buttons)
        buttons.accepted.connect(dialog.accept)
        # buttons.rejected.connect(dialog.reject())

        if dialog.exec_() == QDialog.Accepted:
            Resource = Application.resources("palette")[
                self.cmb_palettes.currentText()]
            Resource.setName(paletteName.text())
            self.currentPalette = Palette(Resource)
            self.currentPalette.setColumnCount(paletteColumns.value())
            self.paletteView.setPalette(self.currentPalette)
            self.slot_fill_combobox()
            self.currentPalette.setComment(paletteComment.toPlainText())
            self.currentPalette.save()
Ejemplo n.º 4
0
class UpdateDialog(QDialog):
    """The dialog for update."""
    def __init__(self):
        super(UpdateDialog, self).__init__()
        vbox = QVBoxLayout(self)
        self.closed = False
        self.setModal(True)
        self.resize(500, 250)

        vbox.addWidget(QLabel("Actualización de la lista de episodios:"))
        self.text = QPlainTextEdit()
        self.text.setReadOnly(True)
        vbox.addWidget(self.text)

        bbox = QDialogButtonBox(QDialogButtonBox.Cancel)
        bbox.rejected.connect(self.reject)
        vbox.addWidget(bbox)

    def append(self, text):
        """Append some text in the dialog."""
        self.text.appendPlainText(text.strip())

    def closeEvent(self, event):
        """It was closed."""
        self.closed = True
Ejemplo n.º 5
0
class InfoScreenWidget(QDialog):
    # Defines and pulls up a notepad type widget, the text of which is saved
    # to .db.
    def __init__(self, mw, db, tribe):
        try:
            QDialog.__init__(self, mw)
            self.db = db
            self.mw = mw
            self.tribe = tribe
            self.setWindowTitle('Info for ' + tribe)
            self.setGeometry(100, 150, 400, 350)
            self.setModal(True)
            self.grid = QGridLayout()
            self.textArea = QPlainTextEdit()
            self.currentInfo = self.db.get_info(tribe)
            self.textArea.appendPlainText(self.currentInfo)
            self.grid.addWidget(self.textArea, 0, 0)
            ok_btn = QPushButton('Ok')
            ok_btn.pressed.connect(self.save_info)
            self.grid.addWidget(ok_btn, 1, 0)
            self.setLayout(self.grid)
            self.show()
        except Exception:
            logger.exception('infoScreen fail')

    def save_info(self):
        logger.debug('Ok clicked on info widget')
        # Once Ok is clicked take text in widget and save to .db
        new_info = self.textArea.toPlainText()
        if self.currentInfo != new_info:  # Only save if changes made
            self.db.update_info(self.tribe, new_info)
            logger.info('new text saved to info')
        self.close()
Ejemplo n.º 6
0
class Widget(QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self._lineedit = QLineEdit(textChanged=self.onTextChanged)
        regex_validator = QRegExpValidator(QRegExp(r"[0-9 ]+"))
        self._lineedit.setValidator(regex_validator)

        self._plaintextedit = QPlainTextEdit()

        self._highlighter = SyntaxHighlighter(self._plaintextedit.document())

        lay = QVBoxLayout(self)
        lay.addWidget(self._lineedit)
        lay.addWidget(self._plaintextedit)

        for i in range(10):
            self._plaintextedit.appendPlainText("line %d" % i)

        self.resize(720, 720)

    @pyqtSlot(str)
    def onTextChanged(self, text):
        fmt = QTextCharFormat()
        fmt.setBackground(QColor("yellow"))
        self._highlighter.clear_highlight()
        for e in text.split():
            line = int(e)
            self._highlighter.highlight_line(line, fmt)
Ejemplo n.º 7
0
class TextEditDialog(QDialog):
    """Text edit dialog with line numbers."""
    def __init__(self, text, apply_callback):
        super().__init__()
        self.apply_callback = apply_callback
        self.textbox = QPlainTextEdit()
        self.textbox.setFont(monospace())
        self.linenos = LineNumberBar(self.textbox)
        buttons = QDialogButtonBox()
        buttons.addButton(buttons.Ok).clicked.connect(self.accept)
        self.setLayout(
            VBoxLayout([
                HBoxLayout([self.linenos, self.textbox], tight=True),
                buttons,
            ]))
        self.setSizeGripEnabled(True)
        self.resize(QSize(600, 400))
        self.textbox.appendPlainText(text)

    def accept(self):
        if self.apply():
            super().accept()

    def apply(self):
        text = self.textbox.toPlainText()
        return self.apply_callback(text)
Ejemplo n.º 8
0
class WorkerMessagesDialog(QDialog):
    """ A dialog to show messages from a parallel worker."""

    def __init__(self, parent=None, window_title="Messages"):
        super(WorkerMessagesDialog, self).__init__(parent)
        self.setWindowTitle(window_title)
        self.setWindowModality(Qt.ApplicationModal)
        layout = QVBoxLayout(self)

        # text edit
        self.textedit = QPlainTextEdit()
        layout.addWidget(self.textedit)

        # buttons
        buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self
        )
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        layout.addWidget(buttons)

    def acceptNewMessage(self, message):
        self.textedit.appendPlainText(message)

    @staticmethod
    def show(parent=None, window_title="Messages"):
        dialog = WorkerMessagesDialog(parent, window_title)
        result = dialog.exec_()
Ejemplo n.º 9
0
class TestWindow(QWidget):

    def __init__(self, *args, **kwargs):
        super(TestWindow, self).__init__(*args, **kwargs)
        layout = QHBoxLayout(self)

        # 左侧原始
        left_group = QGroupBox('原始QSlider', self)
        left_layout = QVBoxLayout(left_group)
        self.leftLabel = QPlainTextEdit(self)
        left_layout.addWidget(self.leftLabel)

        self.leftSlider = QSlider(Qt.Horizontal, self)
        self.leftSlider.valueChanged.connect(self.onLeftChanged)
        left_layout.addWidget(self.leftSlider)

        layout.addWidget(left_group)

        # 右侧低频率变化
        right_group = QGroupBox('LfSlider', self)
        right_layout = QVBoxLayout(right_group)
        self.rightLabel = QPlainTextEdit(self)
        right_layout.addWidget(self.rightLabel)

        self.rightSlider = LfSlider(Qt.Horizontal, self)
        self.rightSlider.valueChanged.connect(self.onRightChanged)
        right_layout.addWidget(self.rightSlider)

        layout.addWidget(right_group)

    def onLeftChanged(self, value):
        self.leftLabel.appendPlainText(datetime.now().strftime("[%H:%M:%S.%f]   ") + str(value))

    def onRightChanged(self, value):
        self.rightLabel.appendPlainText(datetime.now().strftime("[%H:%M:%S.%f]   ") + str(value))
Ejemplo n.º 10
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # Some buttons
        layout = QVBoxLayout()

        self.text = QPlainTextEdit()
        layout.addWidget(self.text)

        btn_run = QPushButton("Execute")
        btn_run.clicked.connect(self.start)

        layout.addWidget(btn_run)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

        # Thread runner
        self.threadpool = QThreadPool()

    def start(self):

        # Create a runner
        self.runner = SubProcessWorker("python ~/dumy.py")
        self.runner.signals.result.connect(self.result)
        self.threadpool.start(self.runner)

    def result(self, s):
        self.text.appendPlainText(s)
Ejemplo n.º 11
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))
class Widget(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.textArea = QPlainTextEdit()
        self.textArea.setFocusPolicy(Qt.NoFocus)

        self.message = QLineEdit()
        self.message.returnPressed.connect(self.sendMessage)

        layout = QVBoxLayout()
        layout.addWidget(self.textArea)
        layout.addWidget(self.message)

        self.timer = QTimer()
        self.timer.timeout.connect(self.displayNewMessage)
        self.timer.start(1000)

        self.setLayout(layout)
        self.show()

    def sendMessage(self):
        server.post(chatUrl, {"name": name, "message": self.message.text()})
        self.message.clear()

    def displayNewMessage(self):
        newMessage = server.get(chatUrl).text
        if newMessage:
            self.textArea.appendPlainText(newMessage)
Ejemplo n.º 13
0
class QTextEditLogger(logging.Handler):  #Log 창 만드는 class
    def __init__(self, parent):
        super().__init__()
        self.widget = QPlainTextEdit(parent)

    def emit(self, record):
        msg = self.format(record)
        self.widget.appendPlainText(msg)
Ejemplo n.º 14
0
class MainWindow(QMainWindow):

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

        self.btn = QPushButton("Execute")
        self.btn.pressed.connect(self.start_process)
        self.text = QPlainTextEdit()
        self.text.setReadOnly(True)

        self.p = None

        l = QVBoxLayout()
        l.addWidget(self.btn)
        l.addWidget(self.text)

        w = QWidget()
        w.setLayout(l)

        self.setCentralWidget(w)

    def start_process(self):
        if self.p is None:
            self.message("Executing process.")
            self.p = QProcess()  # Keep a reference to the QProcess (e.g. on self) while it's running.
            self.p.readyReadStandardOutput.connect(self.handle_stdout)
            self.p.readyReadStandardError.connect(self.handle_stderr)
            self.p.stateChanged.connect(self.handle_state)
            # self.p.finished.connect(self.cleanup)
            self.p.finished.connect(self.process_finished)
            self.p.start("python3", ['external.py'])
    
    def message(self, s):
        self.text.appendPlainText(s)

    def process_finished(self):
        self.message('Process finished')
        self.p = None

    def handle_stderr(self):
        data = self.p.readAllStandardError()
        stderr = bytes(data).decode("utf8")
        self.message(stderr)
    
    def handle_stdout(self):
        data = self.p.readAllStandardOutput()
        stdout = bytes(data).decode("utf8")
        self.message(stdout)

    def handle_state(self, state):
        states = {
            QProcess.NotRunning: 'Not running',
            QProcess.Starting: 'Starting',
            QProcess.Running: 'Running',
        }
        state_name = states[state]
        self.message(f"State changed: {state_name}")
Ejemplo n.º 15
0
class QPlainTextEditLogger(logging.Handler):
    def __init__(self, parent):
        super().__init__()
        self.widget = QPlainTextEdit(parent)
        self.widget.setReadOnly(True)

    def emit(self, record):
        msg = self.format(record)
        self.widget.appendPlainText(msg)
Ejemplo n.º 16
0
class DocumentSearch(QWidget):
    def __init__(self):
        super().__init__()

        self.font = QFont()
        self.font.setFamily("Iosevka")
        self.font.setPointSize(12)

        self.setWindowTitle("Find a document")
        self.initUI()

    def initUI(self):
        self.layout = QVBoxLayout(self)
        self.vbox = QHBoxLayout()
        self.label = QLabel("Enter a file name to search:")

        self.searchButton = QPushButton("Search")
        self.cancelButton = QPushButton("Cancel")
        self.searchResults = QPlainTextEdit()
        self.infoLabel = QLabel("Results will be displayed below")
        self.searchResults.setReadOnly(True)

        self.searchDocumentField = QLineEdit()
        self.searchButton.clicked.connect(self.trigger)
        self.cancelButton.clicked.connect(lambda: self.hide())

        self.searchButton.setAutoDefault(True)

        self.label.setFont(self.font)
        self.infoLabel.setFont(self.font)
        self.searchResults.setFont(self.font)

        self.layout.addWidget(self.label)
        self.layout.addWidget(self.searchDocumentField)
        self.layout.addWidget(self.infoLabel)
        self.layout.addWidget(self.searchResults)

        self.vbox.addWidget(self.searchButton)
        self.vbox.addWidget(self.cancelButton)

        self.layout.addLayout(self.vbox)
        self.setLayout(self.layout)

    def trigger(self):

        file = self.searchDocumentField.text()
        self.thread = grabFiles(file)
        self.thread.start()
        self.thread.fileSignal.connect(self.showPath)

    def showPath(self, path):
        self.searchResults.appendPlainText("\n")
        self.searchResults.appendPlainText(path)

    def run(self):

        self.show()
Ejemplo n.º 17
0
class QPlainTextEditLogger(logging.Handler):
    def __init__(self, parent):
        super().__init__()
        self.widget = QPlainTextEdit(parent)
        self.widget.setReadOnly(True)

    def emit(self, record):
        msg = self.format(record)
        self.widget.appendPlainText(msg)
Ejemplo n.º 18
0
class SerialTerminalWidget(QWidget):
    serTerSignal = pyqtSignal()

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

    def initUI(self):
        self.bundle_dir = os.path.dirname(os.path.abspath(__file__))
        self.layout = QVBoxLayout()
        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 0, 0)

        self.cliTextEdit = QPlainTextEdit(
            "Serial Terminal mode, type 'exit' to return, or 'help'\n\n")
        self.cliTextEdit.setStyleSheet(
            "QPlainTextEdit {background-color:gray; color:white; min-height:590; max-height:800}"
        )
        self.cliInputLine = QLineEdit()
        self.cliInputLine.returnPressed.connect(self.newInputReceived)

        self.layout.addWidget(self.cliTextEdit)
        self.layout.addWidget(self.cliInputLine)
        # self.layout.addStretch(1)

        # Set Main Layout of this page
        self.setLayout(self.layout)

    # Use QTimer
    def setUpdateTimer(self):
        ## Start a timer to rapidly update the plot
        self.sched = QTimer()
        self.sched.timeout.connect(self.checkDataBuffer)

    def checkDataBuffer(self):
        self.serTerSignal.emit()

    def processFeedback(self, feedbackStr):
        date_time = str(datetime.datetime.now()).split()
        (date, time) = date_time
        preStr1 = "[ " + time + " ] "
        preStr2 = "[ " + str(len(feedbackStr)) + " ] "
        self.cliTextEdit.appendPlainText(preStr1 + preStr2 + feedbackStr)

    def start(self):
        self.sched.start(1000)

    def stop(self):
        self.sched.stop()

    def newInputReceived(self):
        waitingText = self.cliInputLine.text()
        if len(waitingText) > 0:
            self.cliTextEdit.appendPlainText("$" + waitingText)
            self.cliInputLine.setText("")
Ejemplo n.º 19
0
    def log_window(self):
        widget = QPlainTextEdit(self)
        widget.setReadOnly(True)
        widget.appendPlainText('Simple Test')

        widget.appendHtml(alertHtml + 'Alert Test')
        widget.appendHtml(notifyHtml + 'Notify Test')
        widget.appendHtml(infoHtml + 'Info Test')
        widget.appendHtml(endHtml + 'Endhtml')
        widget.show()
Ejemplo n.º 20
0
class QPlainTextEditLogger(logging.Handler):
    def __init__(self):
        super().__init__()
        self.widget = QPlainTextEdit()
        self.widget.setReadOnly(True)

    def emit(self, record):
        msg = "{} {}".format(datetime.datetime.now().strftime("[%H:%M:%S]"),
                             self.format(record))
        self.widget.appendPlainText(msg)
Ejemplo n.º 21
0
class InfoDialog(QDialog):
    def __init__(self, title, parent=None):
        super(InfoDialog, self).__init__(parent)
        self.resize(800, 400)
        self.setWindowTitle(title)
        btn = QDialogButtonBox.Ok
        self.btnbox = QDialogButtonBox(btn, self)
        self.btnbox.setDisabled(True)
        self.plainText = QPlainTextEdit(self)

        vbox = QVBoxLayout()
        vbox.addWidget(self.plainText)
        vbox.addWidget(self.btnbox)
        self.btnbox.accepted.connect(self.accept)
        self.done = False
        self.plainText.setReadOnly(True)
        self.thread_cnt = 0
        self.setLayout(vbox)
        # self.plainText.textChanged.connect(self.test)

    def upload_text(self, text):
        self.plainText.appendPlainText(text)
        self.highlihgter()

    def progress_done(self):
        self.btnbox.setDisabled(False)

    def highlihgter(self):
        highlight_rules = [('INFO', Qt.darkGreen), ('Warning', Qt.darkYellow),
                           ('Error', Qt.darkRed)]

        cursor = self.plainText.textCursor()
        text = self.plainText.toPlainText()
        for keyword, color in highlight_rules:
            regex = QRegExp(keyword)
            index = regex.indexIn(text)
            fmt = QTextCharFormat()
            fmt.setForeground(color)
            while index != -1:
                cursor.setPosition(index)
                cursor.movePosition(QTextCursor.EndOfWord, 1)
                cursor.mergeCharFormat(fmt)
                # Move to the next match
                pos = index + regex.matchedLength()
                index = regex.indexIn(text, pos)

    def accept(self):
        self.plainText.setPlainText('')
        self.btnbox.setDisabled(True)
        super(InfoDialog, self).accept()

    def reject(self):
        self.plainText.setPlainText('')
        self.btnbox.setDisabled(True)
        super(InfoDialog, self).reject()
Ejemplo n.º 22
0
class QLogger(logging.Handler):
  def __init__(self, parent):
    super().__init__()
    self.widget = QPlainTextEdit(parent)
    self.widget.setReadOnly(True)

    self.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))

  def emit(self, record):
    msg = self.format(record)
    self.widget.appendPlainText(msg)
Ejemplo n.º 23
0
class TextLogElement(object):
    def __init__(self,
                 maximum_block_count: int = 1000,
                 font_size_pt: int = 10,
                 font_family: str = "Courier",
                 title: str = "Log") -> None:
        # For nested layouts: (1) create everything, (2) lay out
        self.log_group = StyledQGroupBox(title)
        log_layout_1 = QVBoxLayout()
        log_layout_2 = QHBoxLayout()
        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.log.setMaximumBlockCount(maximum_block_count)

        font = self.log.font()
        font.setFamily(font_family)
        font.setPointSize(font_size_pt)

        log_clear_button = QPushButton('Clear log')
        log_clear_button.clicked.connect(self.log.clear)
        log_copy_button = QPushButton('Copy to clipboard')
        log_copy_button.clicked.connect(self.copy_whole_log)
        log_layout_2.addWidget(log_clear_button)
        log_layout_2.addWidget(log_copy_button)
        log_layout_2.addStretch(1)
        log_layout_1.addWidget(self.log)
        log_layout_1.addLayout(log_layout_2)
        self.log_group.setLayout(log_layout_1)

    def get_widget(self) -> QWidget:
        return self.log_group

    def add(self, msg: str) -> None:
        # http://stackoverflow.com/questions/16568451
        # self.log.moveCursor(QTextCursor.End)
        self.log.appendPlainText(msg)
        # ... will append it as a *paragraph*, i.e. no need to add a newline
        # self.scroll_to_end_of_log()

    def copy_whole_log(self) -> None:
        # Ctrl-C will copy the selected parts.
        # log.copy() will copy the selected parts.
        self.log.selectAll()
        self.log.copy()
        self.log.moveCursor(QTextCursor.End)
        self.scroll_to_end_of_log()

    def scroll_to_end_of_log(self) -> None:
        vsb = self.log.verticalScrollBar()
        vsb.setValue(vsb.maximum())
        hsb = self.log.horizontalScrollBar()
        hsb.setValue(0)
Ejemplo n.º 24
0
class TextLogElement(object):
    def __init__(self,
                 maximum_block_count: int = 1000,
                 font_size_pt: int = 10,
                 font_family: str = "Courier",
                 title: str = "Log") -> None:
        # For nested layouts: (1) create everything, (2) lay out
        self.log_group = StyledQGroupBox(title)
        log_layout_1 = QVBoxLayout()
        log_layout_2 = QHBoxLayout()
        self.log = QPlainTextEdit()
        self.log.setReadOnly(True)
        self.log.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.log.setMaximumBlockCount(maximum_block_count)

        font = self.log.font()
        font.setFamily(font_family)
        font.setPointSize(font_size_pt)

        log_clear_button = QPushButton('Clear log')
        log_clear_button.clicked.connect(self.log.clear)
        log_copy_button = QPushButton('Copy to clipboard')
        log_copy_button.clicked.connect(self.copy_whole_log)
        log_layout_2.addWidget(log_clear_button)
        log_layout_2.addWidget(log_copy_button)
        log_layout_2.addStretch(1)
        log_layout_1.addWidget(self.log)
        log_layout_1.addLayout(log_layout_2)
        self.log_group.setLayout(log_layout_1)

    def get_widget(self) -> QWidget:
        return self.log_group

    def add(self, msg: str) -> None:
        # http://stackoverflow.com/questions/16568451
        # self.log.moveCursor(QTextCursor.End)
        self.log.appendPlainText(msg)
        # ... will append it as a *paragraph*, i.e. no need to add a newline
        # self.scroll_to_end_of_log()

    def copy_whole_log(self) -> None:
        # Ctrl-C will copy the selected parts.
        # log.copy() will copy the selected parts.
        self.log.selectAll()
        self.log.copy()
        self.log.moveCursor(QTextCursor.End)
        self.scroll_to_end_of_log()

    def scroll_to_end_of_log(self) -> None:
        vsb = self.log.verticalScrollBar()
        vsb.setValue(vsb.maximum())
        hsb = self.log.horizontalScrollBar()
        hsb.setValue(0)
Ejemplo n.º 25
0
class newTextBox():
    def __init__(self, parent, size, pos, init_text=""):
        #self.textBox = QLineEdit(parent)
        self.textBox = QPlainTextEdit(parent)
        self.textBox.appendPlainText(init_text)
        self.textBox.setReadOnly(True)
        if size and pos:
            self.textBox.setGeometry(pos[0], pos[1], size[0], size[1])
            #self.textBox.resize(size[0], size[1])
            #self.textBox.setMaximumHeight(size[1])

    def showText(self, text):
        self.textBox.appendPlainText(text)
Ejemplo n.º 26
0
    def __init__(self):
        super().__init__()
        uic.loadUi('menu.ui', self)
        # подгружаем файл из designer

        # подключаем кнопки
        self.play.clicked.connect(self.Show_lvl)
        self.rules.clicked.connect(self.Show_rules)

        print_text = QPlainTextEdit(self)
        print_text.resize(181, 51)
        print_text.move(730, 189)
        print_text.appendPlainText(str(max(best_score)))
Ejemplo n.º 27
0
class QTextEditLogger(logging.Handler, QObject):
    sigAppendLog = pyqtSignal(str)
    MAX_LENGTH = 300

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

        self._init_ui(parent)

        # self.cursor = QTextCursor(self.text_widget.document())
        self.sigAppendLog.connect(self.append_log)
        self.setFormatter(
            logging.Formatter(
                '%(levelname)s %(module)s:%(funcName)s %(message)s'))
        logging.getLogger().addHandler(self)
        self.setLevel(logging.DEBUG)

    def _init_ui(self, parent):
        self.widget = QWidget(parent)
        self.level_box = QComboBox(self.widget)
        self.level_box.addItems('DEBUG INFO WARNING ERROR'.split())
        self.level_box.currentIndexChanged.connect(self.level_changed)
        self.text_widget = QPlainTextEdit(self.widget)
        self.text_widget.setReadOnly(True)
        layout = QGridLayout(self.widget)

        layout.addWidget(self.level_box, 0, 0)
        layout.addWidget(self.text_widget, 1, 0)

    @pyqtSlot(int, name='levelBoxIndexChanged')
    def level_changed(self, idx):
        text = self.level_box.currentText()
        self.setLevel(_LEVEL_DICT[text])

    @pyqtSlot(str, name='appendLog')
    def append_log(self, log: str):
        level, *message = log.split()
        message = _set_html_color(' '.join(message), level)
        if len(message) > self.MAX_LENGTH:
            self.text_widget.appendPlainText('')
        self.text_widget.appendHtml(message)
        if len(message) > self.MAX_LENGTH:
            self.text_widget.appendPlainText('')

    def emit(self, record):
        msg = self.format(record)
        try:
            self.sigAppendLog.emit(msg)
        except RuntimeError:
            pass
Ejemplo n.º 28
0
class RunWidget(QWidget):

    finish_signal = pyqtSignal()
    control_mouse_and_keyboard_start_signal = pyqtSignal()
    control_mouse_and_keyboard_end_signal = pyqtSignal()

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

    def initUI(self):
        self.go_button = QPushButton('下载')
        self.go_button.setMinimumHeight(35)
        self.state_show = QPlainTextEdit()
        self.state_show.setReadOnly(True)

        self.run_box = QVBoxLayout(self)
        self.run_box.addWidget(self.go_button)
        self.run_box.addWidget(self.state_show)
        self.run_box.setAlignment(Qt.AlignHCenter | Qt.AlignTop)

        self.state_show.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        self.setLayout(self.run_box)

    def appendText(self, text):
        if text.strip():
            self.state_show.appendPlainText(text.strip())

    def setGoButtonEnabeld(self, bool):
        self.go_button.setEnabled(bool)

    def download(self,
                 read_mode,
                 get_links_from_wechat_mode,
                 write,
                 write_mode,
                 link=''):
        self.dl = Download(read_mode, get_links_from_wechat_mode, write,
                           write_mode, link)
        self.dl.print_signal.connect(self.appendText)
        self.dl.finish_signal.connect(
            lambda b=True: self.setGoButtonEnabeld(b))
        self.dl.finish_signal.connect(self.finish_signal.emit)
        self.dl.control_mouse_and_keyboard_start_signal.connect(
            self.control_mouse_and_keyboard_start_signal.emit)
        self.dl.control_mouse_and_keyboard_end_signal.connect(
            self.control_mouse_and_keyboard_end_signal.emit)
        self.setGoButtonEnabeld(False)
        self.dl.start()
Ejemplo n.º 29
0
class QPlainTextEditLogger(logging.Handler):
    def __init__(self, parent):
        super().__init__()
        self.widget = QPlainTextEdit(parent)
        self.widget.setReadOnly(True)
        self.widget.setStyleSheet("Color:white;"
                                  "background-color:rgba(0, 0, 0, 150);")
        self.widget.verticalScrollBar().setValue(0)

    def emit(self, record):
        msg = self.format(record)
        self.widget.appendPlainText(msg)
        self.widget.verticalScrollBar().setValue(
            self.widget.verticalScrollBar().maximum())
Ejemplo n.º 30
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()
Ejemplo n.º 31
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()
Ejemplo n.º 32
0
 def InitWindow(self):
     self.setWindowIcon(QtGui.QIcon("transistor.jpg"))
     self.setWindowTitle(self.title)
     self.setGeometry(self.top, self.width, self.height, self.width)
     vbox = QVBoxLayout()
     plainTextEdit = QPlainTextEdit()
     vbox.addWidget(plainTextEdit)
     plainTextEdit.setPlaceholderText(
         "This is the placeholder for the plain")
     #plainTextEdit.setReadOnly(True)
     text = "Please suck my c**k"
     plainTextEdit.appendPlainText(text)
     #plainTextEdit.setUndoRedoEnabled(False)
     self.setLayout(vbox)
Ejemplo n.º 33
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)
Ejemplo n.º 34
0
class Window(QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        grid = QGridLayout()
        grid.addWidget(self.create_top_group(), 0, 0)
        grid.addLayout(self.create_mid_group(), 1, 0)
        grid.addWidget(self.create_bottom_group(), 2, 0)
        self.setLayout(grid)

        self.setWindowTitle("UJ Editor")
        self.resize(1280, 640)
        # self.create_actions()

    # def __wiggets_to_layout(self, layout, *widgets):
    #     for widget in widgets:
    #         layout.addWidget(widget)

    def __mix_to_layout(self, layout, *mix):
        for item in mix:
            if isinstance(item, QWidget):
                layout.addWidget(item)
            if isinstance(item, QLayout):
                layout.addLayout(item)

    def create_top_group(self):
        group_box = QGroupBox()
        self.import_button = QPushButton('&Import UJ')
        self.import_button.clicked.connect(self.import_uj)
        export_button = QPushButton('&Export UJ')
        export_button.clicked.connect(self.export_uj)
        self.uj_name = LabelLineEdit('UJ Name')
        hbox = QHBoxLayout()
        hbox.setContentsMargins(0,0,0,0)
        self.__mix_to_layout(hbox, self.import_button, export_button, self.uj_name.layout)
        group_box.setLayout(hbox)
        group_box.setMaximumHeight(60)
        return group_box

    def create_mid_group(self):
        self.ddi_tree = QTreeWidget()
        self.ddi_tree.itemSelectionChanged.connect(self.show_ddi_details)

        ddi_details = QGroupBox()
        ddi_details_layout = QGridLayout()
        ddi_details_layout.setContentsMargins(0,0,0,0)
        ddi_details_layout.addWidget(self.create_common_ddi_details(), 0, 0, 1, 1)
        ddi_details_layout.addWidget(self.create_specific_ddi_details(), 1, 0, 3, 1)
        ddi_details.setLayout(ddi_details_layout)

        self.step_tree = QTreeWidget()
        self.step_tree.itemSelectionChanged.connect(self.show_step_details)
        step_details = QGroupBox()
        step_details_layout = QGridLayout()
        step_details_layout.setContentsMargins(0,0,0,0)
        step_details_layout.addWidget(self.create_common_step_details(), 0, 0, 1, 1)
        # step_details_layout.addWidget(self.create_specific_step_details(), 1, 0, 3, 1)
        step_details.setLayout(step_details_layout)

        splitter = QSplitter(self)
        splitter.addWidget(self.ddi_tree)
        splitter.addWidget(ddi_details)
        splitter.addWidget(self.step_tree)
        splitter.addWidget(step_details)

        hbox = QHBoxLayout()
        hbox.setContentsMargins(0,0,0,0)
        # self.__mix_to_layout(hbox, self.ddi_tree, ddi_details, self.step_tree, step_details)
        hbox.addWidget(splitter)
        # group_box.setLayout(hbox)
        return hbox

    def create_bottom_group(self):
        group_box = QGroupBox()
        group_box.setMaximumHeight(200)
        self.debug_edit = QPlainTextEdit()
        self.debug_edit.setMaximumHeight(160)
        hbox = QHBoxLayout()
        hbox.setContentsMargins(0,0,0,0)
        # hbox.setSizeConstraint(200)
        hbox.addWidget(self.debug_edit)
        group_box.setLayout(hbox)
        return group_box

    def create_common_ddi_details(self):
        group_box = QGroupBox()
        vbox = QVBoxLayout()
        self.ddi_description = LabelLineEdit('Description')
        type_name_layout = QHBoxLayout()
        type_name_layout.setContentsMargins(0,0,0,0)
        self.ddi_name = LabelLineEdit('DDI Name')
        self.ddi_type = LabelComboBox('Type', DDI_TYPES)
        self.__mix_to_layout(type_name_layout, self.ddi_type.layout, self.ddi_name.layout)
        self.ddi_sharing = LabelButtonGroup('State Sharing', {'SCRIPT  ': '&Single User', 'THREAD  ': '&All Run Users'})
        self.ddi_refresh = LabelButtonGroup('Refresh Condition', {'C': 'Every Cycle', 'R': 'Once per Run', 'T': 'Every Time', 'U': 'Once per User'})
        vbox.setContentsMargins(0,0,0,0)
        self.__mix_to_layout(vbox, type_name_layout, self.ddi_description.layout, self.ddi_sharing.layout, self.ddi_refresh.layout)
        group_box.setLayout(vbox)
        return group_box


    # ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()
    def create_specific_ddi_details(self):
        group_box = QGroupBox()
        self.ddi_specific_layout = QVBoxLayout()
        self.ddi_specific_layout.setContentsMargins(0,0,0,0)
        # self.value_layout = self.create_ddi_value()
        self.ddi_value_widget = LabelLineEdit('Value')
        self.ddi_selector_widget = LabelComboBox('Selector', SELECTOR_TYPES)
        # self.ddi_specific_layout.addWidget(self.ddi_value_widget)
        self.ddi_specific_layout.addLayout(self.ddi_value_widget.layout)
        self.ddi_specific_layout.addLayout(self.ddi_selector_widget.layout)

        self.ddi_date = DateFieldsGroup()
        self.ddi_specific_layout.addLayout(self.ddi_date.layout)

        self.ddi_delimiter_character_widget = LabelLineEdit('Delimiter:')
        self.ddi_delimiter_character_widget.line_edit.setMaxLength(1)
        self.ddi_delimited_filename_widget = LabelLineEdit('File Name:')
        self.ddi_delimited_file_picker_button = QPushButton('&Load Data File')
        self.ddi_delimited_file_picker_button.clicked.connect(self.load_data_file)
        delimited_layout = QHBoxLayout()
        delimited_layout.setContentsMargins(0,0,0,0)
        delimited_layout.addLayout(self.ddi_delimiter_character_widget.layout, stretch = 0)
        delimited_layout.addLayout(self.ddi_delimited_filename_widget.layout, stretch = 2)
        delimited_layout.addWidget(self.ddi_delimited_file_picker_button, stretch = 1)
        self.ddi_specific_layout.addLayout(delimited_layout)

        self.ddi_column_index_widget = LabelLineEdit('Column Index:')
        self.ddi_column_index_widget.line_edit.setInputMask('999')
        self.ddi_specific_layout.addLayout(self.ddi_column_index_widget.layout)

        self.ddi_list_table = MyTableWidget()
        self.ddi_specific_layout.addLayout(self.ddi_list_table.layout)

        self.ddi_related_ddi = LabelComboBox('Related to:')
        self.ddi_specific_layout.addLayout(self.ddi_related_ddi.layout)

        self.ddi_response_source_step = LabelComboBox('Source Step:')
        self.ddi_specific_layout.addLayout(self.ddi_response_source_step.layout)

        self.ddi_siphon_table = RowControlTableWidget([('type', list(SIPHON_TYPES.values())), ('start', ''), ('end', ''), ('index', '')])
        self.ddi_specific_layout.addLayout(self.ddi_siphon_table.layout)

        self.ddi_auto_correlate_type = LabelComboBox('Field Type:', { z:z for z in ['Repeated Fields', 'Known Fields'] })
        self.ddi_specific_layout.addLayout(self.ddi_auto_correlate_type.layout)
        self.ddi_auto_correlate_name = LabelComboBox('Field Name:')
        self.ddi_specific_layout.addLayout(self.ddi_auto_correlate_name.layout)
        self.ddi_auto_correlate_appears_in = LabelCheckboxesGroup('Appears In:', ['URL', 'Post', 'Headers'])
        self.ddi_specific_layout.addLayout(self.ddi_auto_correlate_appears_in.layout)

        hbox = QHBoxLayout()
        hbox.setContentsMargins(0,0,0,0)
        self.ddi_auto_increment_starting_value = LabelLineEdit('Starting Value:')
        hbox.addLayout(self.ddi_auto_increment_starting_value.layout)
        self.ddi_auto_increment_increment = LabelLineEdit('Increment:')
        hbox.addLayout(self.ddi_auto_increment_increment.layout)
        self.ddi_auto_increment_prefix = LabelLineEdit('Prefix:')
        hbox.addLayout(self.ddi_auto_increment_prefix.layout)
        self.ddi_auto_increment_suffix = LabelLineEdit('Suffix:')
        hbox.addLayout(self.ddi_auto_increment_suffix.layout)
        self.ddi_auto_increment_min_lenght = LabelLineEdit('Minimum Length:')
        hbox.addLayout(self.ddi_auto_increment_min_lenght.layout)
        self.ddi_specific_layout.addLayout(hbox)

        group_box.setLayout(self.ddi_specific_layout)
        return group_box

    # ()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()

    def create_common_step_details(self):
        group_box = QGroupBox()
        vbox = QVBoxLayout()
        vbox.setContentsMargins(0,0,0,0)
        vbox.setAlignment(Qt.AlignTop)
        name_sleep_layout = QHBoxLayout()
        name_sleep_layout.setContentsMargins(0,0,0,0)
        self.step_name = LabelLineEdit('Name')
        name_sleep_layout.addLayout(self.step_name.layout)
        self.step_pre_time = LabelLineEdit('Sleep Time (sec)')
        name_sleep_layout.addLayout(self.step_pre_time.layout)
        vbox.addLayout(name_sleep_layout)
        self.step_description = LabelLineEdit('Description')
        vbox.addLayout(self.step_description.layout)
        self.step_checkboxes = LabelCheckboxesGroup('', ['Run First Cycle Only', 'Run Last Cycle Only', 'Count as Transaction', 'Process Response', 'Execute Separately'])
        vbox.addLayout(self.step_checkboxes.layout)
        request_type_content_type_layout = QHBoxLayout()
        self.request_type = LabelComboBox('Type', { z:z for z in STEP_REQUEST_TYPES })
        request_type_content_type_layout.addLayout(self.request_type.layout)
        self.content_type = LabelComboBox('Content-Type', { z:z for z in STEP_CONTENT_TYPES })
        request_type_content_type_layout.addLayout(self.content_type.layout)
        # self.content_type.combo_box.currentIndexChanged[str].connect(self.update_content_subtypes)
        # # what's the point of having type and subtypes? the one sent with headers is the subtype - it should be the only selection
        # self.content_subtype = LabelComboBox('', { z:z for z in STEP_CONTENT_TYPES['form'] })
        # request_type_content_type_layout.addLayout(self.content_subtype.layout)
        vbox.addLayout(request_type_content_type_layout)
        self.step_url = LabelLineEdit('URL')
        vbox.addLayout(self.step_url.layout)
        self.step_url_params_table = RowControlTableWidget([('Parameter', ''), ('Value', '')])
        vbox.addLayout(self.step_url_params_table.layout)
        self.step_post_params_table = RowControlTableWidget([('Parameter', ''), ('Value', '')])
        vbox.addLayout(self.step_post_params_table.layout)
        self.step_post_block = QPlainTextEdit()
        vbox.addWidget(self.step_post_block)
        success_validation_layout = QHBoxLayout()
        success_validation_layout.setContentsMargins(0,0,0,0)
        self.step_validation_type = LabelComboBox('Success Validation', {'PLAIN': 'Plain Text','REGEX': 'Regular Expression'})
        success_validation_layout.addLayout(self.step_validation_type.layout)
        self.step_validation_text = LabelLineEdit('')
        success_validation_layout.addLayout(self.step_validation_text.layout)
        self.max_response = LabelLineEdit('Max acceptable response time')
        success_validation_layout.addLayout(self.max_response.layout)
        vbox.addLayout(success_validation_layout)
        self.step_dynamic_content = LabelCheckboxesGroup('Select content types to be handled automatically', ['images', 'css', 'javaScript'])
        vbox.addLayout(self.step_dynamic_content.layout)

        flow_control_line1_layout = QHBoxLayout()
        self.step_flow_control_type = LabelComboBox('Flow Control', {'': 'GoTo', 'RESPONSE': 'Response Based', 'CONDTITIONAL': 'Conditional', 'PERCENTAGE': 'Percentage Based',
                                                                     'DDLOOP': 'Dynamic Data Loop', 'VARIABLELOOP': 'Variable Loop', 'FIXEDLOOP': 'Fixed Loop'})
        flow_control_line1_layout.addLayout(self.step_flow_control_type.layout)
        self.step_flow_target_plus = LabelComboBox('Step', {'NEXT_STEP': 'Next Step', 'END_CYCLE': 'End Cycle', 'END_USER': '******'})
        flow_control_line1_layout.addLayout(self.step_flow_target_plus.layout)
        self.step_flow_sleep = LabelLineEdit('Sleep Time (sec)')
        flow_control_line1_layout.addLayout(self.step_flow_sleep.layout)
        vbox.addLayout(flow_control_line1_layout)

        flow_control_line2_layout = QHBoxLayout()
        self.step_flow_ddl_ddi = LabelComboBox('Dynamic Data Item', {})
        flow_control_line2_layout.addLayout(self.step_flow_ddl_ddi.layout)
        self.step_flow_varloop_start = LabelLineEdit('Minimum Iterations')
        flow_control_line2_layout.addLayout(self.step_flow_varloop_start.layout)
        self.step_flow_varloop_end = LabelLineEdit('Maximum Iterations')
        flow_control_line2_layout.addLayout(self.step_flow_varloop_end.layout)
        self.step_flow_fixloop = LabelLineEdit('Iterations')
        flow_control_line2_layout.addLayout(self.step_flow_fixloop.layout)

        self.step_flow_conditional_true = LabelComboBox('If true, go to', {'NEXT_STEP': 'Next Step', 'END_CYCLE': 'End Cycle', 'END_USER': '******'})
        flow_control_line2_layout.addLayout(self.step_flow_conditional_true.layout)
        self.step_flow_conditional_false = LabelComboBox('otherwise, go to', {'NEXT_STEP': 'Next Step', 'END_CYCLE': 'End Cycle', 'END_USER': '******'})
        flow_control_line2_layout.addLayout(self.step_flow_conditional_false.layout)
        vbox.addLayout(flow_control_line2_layout)

        self.step_flow_response_table = RowControlTableWidget([('Response Step', []), ('Match Criteria', ''), ('Step', []), ('Sleep Time', '0.0')])
        vbox.addLayout(self.step_flow_response_table.layout)
        self.step_flow_percentage_table = RowControlTableWidget([('Percentage', ''), ('Step', []), ('Sleep Time', '0.0')])
        self.step_flow_percentage_table.set_text([['100', {'Next Step': ['Next Step', 'End Cycle', 'End User']}, '0.0']])
        vbox.addLayout(self.step_flow_percentage_table.layout)
        self.step_flow_conditional_table = RowControlTableWidget([('Phrase 1', ''), ('Conditional',  ['<', '<=', '=', '=>', '>', '!=', 'in', 'not in']), ('Phrase 2', ''), ('Operator', ['AND', 'OR'])])
        vbox.addLayout(self.step_flow_conditional_table.layout)


        group_box.setLayout(vbox)
        return group_box


    def create_specific_step_details(self):
        pass




# ------------------------------------------------------ end of creations ----------------------------------------------------------

    # def create_actions(self):
    #     self.import_act = QAction("&Import...", self, shortcut="Ctrl+I", triggered=self.import_uj)
    #     self.export_act = QAction("&Export...", self, shortcut="Ctrl+E", triggered=self.export_uj)

    # def update_content_subtypes(self, item):
    #     # item is supposed to be the text value of the combobox selection
    #     print('reached function update_content_subtypes with item=', item)



    def debug__(self, message):
        self.debug_edit.appendPlainText(message)

    def load_data_file(self):
        filename = QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
        self.ddi_delimited_filename_widget.set_text(filename[0])
        self.selected_ddi.file_name = filename

    def import_uj(self, filename=[]):
        if not filename:
            filename = QFileDialog.getOpenFileName(self, 'Open File', os.getenv('HOME'))
        self.uj = UserJourney('')
        self.uj.import_uj(filename[0])
        self.uj_name.set_text(self.uj.name)

        ddi_nodes = []
        for ddi in self.uj.dditems:
            new_ddi_node = QTreeWidgetItem()
            new_ddi_node.setText(0, ddi.name)
            ddi_nodes.append(new_ddi_node)

        self.ddi_tree.addTopLevelItems(ddi_nodes)

        date_type_ddis = self.uj.find_ddis_by_attribute('type', 'DATE    ')
        if date_type_ddis:
            self.ddi_date.related_ddi_box.reset_items({z.name:z.name for z in date_type_ddis})

        relatable_type_ddis = []
        for type_ in ['FLATFILE', 'LIST    ', 'RESPONSE']:
            relatable_type_ddis.extend(self.uj.find_ddis_by_attribute('type', type_))
        if relatable_type_ddis:
            self.ddi_related_ddi.reset_items({z.name:z.name for z in relatable_type_ddis})

        sourceable_step_names = []
        sourceable_steps = self.uj.find_steps_by_attribute('name_user_defined', True)
        if sourceable_steps:
            self.ddi_response_source_step.reset_items({ str(z.id):z.name for z in sourceable_steps })
            sourceable_step_names = [ z.name for z in sourceable_steps ]

        self.correlated_names = { z.field_name:z.field_name for z in self.uj.find_ddis_by_attribute('type', 'AUTOCORR') } # if z.field_type == 'Repeated Fields' }
        self.ddi_auto_correlate_name.reset_items(self.correlated_names)

        groupnodes = []
        for stepgroup in self.uj.stepgroups:
            new_group_node = QTreeWidgetItem()
            new_group_node.setText(0, stepgroup.name)
            stepnodes = []
            for step in stepgroup.steps:
                new_step_node = QTreeWidgetItem(new_group_node)
                new_step_node.setText(0, step.name)
                stepnodes.append(new_step_node)

            groupnodes.append(new_group_node)

        self.step_tree.addTopLevelItems(groupnodes)

        self.step_flow_response_table.reset_row_template([('Response Step', sourceable_step_names), ('Match Criteria', ''), ('Step', ['Next Step'] + sourceable_step_names + ['End Cycle', 'End User']), ('Sleep Time', '0.0')])
        self.step_flow_percentage_table.reset_row_template([('Percentage', ''), ('Step', ['Next Step'] + sourceable_step_names + ['End Cycle', 'End User']), ('Sleep Time', '0.0')])
        # self.step_flow_percentage_table.set_text([['100', {'Next Step': ['Next Step', 'End Cycle', 'End User']}, '0.0']])

    def export_uj(self):
        pass
        # convert SIPHON_TYPES from full text to code before passing them to self.uj...

    def show_ddi_details(self):
        selected_ddi_name = self.ddi_tree.selectedItems()[0].text(0)
        self.selected_ddi = self.uj.find_ddi_by_name(selected_ddi_name)

        # Common
        self.ddi_name.set_text(selected_ddi_name)
        self.ddi_description.set_text(self.selected_ddi.description)
        self.ddi_type.set_text(DDI_TYPES[self.selected_ddi.type])
        self.ddi_sharing.set_text(self.selected_ddi.scope)
        self.ddi_refresh.set_text(self.selected_ddi.lifecycle)

        # Specific
        ddi_specific_fields = [
            self.ddi_value_widget,
            self.ddi_selector_widget,
            self.ddi_delimiter_character_widget,
            self.ddi_delimited_filename_widget,
            self.ddi_delimited_file_picker_button,
            self.ddi_column_index_widget,
            self.ddi_date,
            self.ddi_list_table,
            self.ddi_related_ddi,
            self.ddi_response_source_step,
            self.ddi_siphon_table,
            self.ddi_auto_correlate_type,
            self.ddi_auto_correlate_name,
            self.ddi_auto_correlate_appears_in,
            self.ddi_auto_increment_starting_value,
            self.ddi_auto_increment_increment,
            self.ddi_auto_increment_prefix,
            self.ddi_auto_increment_suffix,
            self.ddi_auto_increment_min_lenght,
        ]

        ddi_type_mappings = {
            ConstantDDI: {self.ddi_value_widget: 'value'},
            DateDDI: {
                self.ddi_date: [
                                'starting_point',
                                'starting_value',
                                'starting_value',
                                'offset_type',
                                'format',
                                'first_offset_sign',
                                'first_offset_value',
                                'first_offset_unit',
                                'second_offset_sign',
                                'second_offset_value',
                                'second_offset_unit',
                                ]
            },
            DelimitedFileDDI: {
                self.ddi_delimiter_character_widget: 'delimiter',
                self.ddi_delimited_filename_widget: 'file_name',
                self.ddi_delimited_file_picker_button: '',
                self.ddi_column_index_widget: 'column',
                self.ddi_selector_widget: 'selection_type',
            },
            ListDDI: {self.ddi_selector_widget: 'selection_type', self.ddi_column_index_widget: 'column', self.ddi_list_table: ['table']},
            VariableDDI: {self.ddi_value_widget: 'value'},
            RelatedDDI: {self.ddi_column_index_widget: 'column', self.ddi_related_ddi: 'associated'},
            ResponseDDI: {self.ddi_selector_widget: 'selection_type', self.ddi_column_index_widget: 'column', self.ddi_response_source_step: 'source_step_id', self.ddi_siphon_table: 'dict_siphons'},
            AutoCorrelatedDDI: {self.ddi_auto_correlate_type: 'field_type', self.ddi_auto_correlate_name: 'field_name', self.ddi_auto_correlate_appears_in: ['find_in_url', 'find_in_post', 'find_in_headers']},
            AutoIncrementDDI: {self.ddi_auto_increment_starting_value: 'starting_value', self.ddi_auto_increment_increment: 'increment', self.ddi_auto_increment_prefix: 'prefix',
                               self.ddi_auto_increment_suffix: 'suffix', self.ddi_auto_increment_min_lenght: 'minimum_length'},
        }

        object_attribute_pairs = ddi_type_mappings[type(self.selected_ddi)]
        # print('obj', object_attribute_pairs )
        # print('selected type', type(self.selected_ddi) ,'selected item expected attributes', object_attribute_pairs.values() )
        for field in ddi_specific_fields:
            debug_message = ''
            # print('field', field, 'values', object_attribute_pairs.values())
            if field in object_attribute_pairs.keys():
                field.show()
                target_attribute_name = object_attribute_pairs[field]
                # print('target attribute', target_attribute_name)
                if isinstance(target_attribute_name, str):
                    if target_attribute_name != '':
                        # print('ttt', type(getattr(self.selected_ddi, object_attribute_pairs[field])))
                        value = getattr(self.selected_ddi, object_attribute_pairs[field])
                        if callable(value):
                            value = value()
                        else:
                            value = str(value)
                        field.set_text(value)
                        # print('target attribute value', value)

                        # --- debug ---
                        if field == self.ddi_value_widget:
                            debug_message += 'field: '+str(field)+'; uj object value: '+ str(value) + '\n'
                else:
                    # currently this section covers for Date group & table widget
                    values =[]
                    for attribute in target_attribute_name:
                        try:
                            # values.append(str(getattr(self.selected_ddi, attribute)))
                            values.append(getattr(self.selected_ddi, attribute))
                        except AttributeError:
                            pass

                        # print('values', values)
                    field.set_values(*values)
                    # where set_values(self, starting_point, starting_fixed_edit, starting_related_ddi, offset, sign1='', amount1=0, unit1='', sign2='', amount2=0, unit2=''):
                    #  i.e. the attributes that may be missing are set as optional arguments


            else:
                field.hide()

            # --- debug ---
            if field == self.ddi_response_source_step:
                debug_message += 'ui object value: ' + self.ddi_response_source_step.text() + '; visibility: ' + str(self.ddi_response_source_step.combo_box.isVisible()) + '\n'
                self.debug__(debug_message)



    def show_step_details(self):
        selected_step_name = self.step_tree.selectedItems()[0].text(0)
        self.selected_step = self.uj.find_step_by_name(selected_step_name)

        # self.ddi_name.set_text(selected_ddi_name)
        # self.ddi_description.set_text(self.selected_ddi.description)
        # self.ddi_type.set_text(DDI_TYPES[self.selected_ddi.type])
        # self.ddi_sharing.set_text(self.selected_ddi.scope)
        # self.ddi_refresh.set_text(self.selected_ddi.lifecycle)

        self.step_name.set_text(selected_step_name)
        self.step_pre_time.set_text(self.selected_step.sleeptime)
        self.step_description.set_text(self.selected_step.description)
        # print(self.selected_step.first_cycle_only, self.selected_step.last_cycle_only, self.selected_step.count_as_transaction, self.selected_step.processresponse, self.selected_step.execute_separately)
        self.step_checkboxes.set_values(self.selected_step.first_cycle_only, self.selected_step.last_cycle_only, self.selected_step.count_as_transaction,
                                         self.selected_step.processresponse, self.selected_step.execute_separately)
        # ['Run First Cycle Only', 'Run Last Cycle Only', 'Count as Transaction', 'Process Response', 'Execute Separately'])
        self.request_type.set_text(self.selected_step.type)
        selected_step_content_type = ''
        for header in self.selected_step.headers:
            if header['name'] == 'Content-Type':
                selected_step_content_type = header['value']
        self.content_type.set_text(selected_step_content_type)
        self.step_url.set_text(self.selected_step.request)
        if self.selected_step.get_itmes == []:
            self.step_url_params_table.hide()
        else:
            self.step_url_params_table.show()
            get_params = []
            for item in self.selected_step.get_itmes:
                get_params.append([item['name'], item['value']])
            self.step_url_params_table.set_text(get_params)

        if self.selected_step.post_items == []:
            self.step_post_params_table.hide()
            self.step_post_block.hide()
        else:
            if self.selected_step.post_items[0]['name'] == '':
                self.step_post_params_table.hide()
                self.step_post_block.show()
                self.step_post_block.appendPlainText(self.selected_step.post_items[0]['value'])
            else:
                self.step_post_block.hide()
                self.step_post_params_table.show()
                self.step_post_params_table.set_text([ [z['name'], z['value']] for z in self.selected_step.post_items])

        selected_step_validation_type = ''
        for item in self.selected_step.items:
            if item['name'] == 'ValidationType':
                selected_step_validation_type = item['value']

        self.step_validation_type.set_text(selected_step_validation_type)
        self.step_validation_text.set_text(self.selected_step.success)

        selected_step_max_response = ''
        for item in self.selected_step.items:
            if item['name'] == 'MaxResponseTime':
                selected_step_max_response = item['value']
        if self.selected_step.is_lead():
            self.max_response.show()
            self.max_response.set_text(selected_step_max_response)
        else:
            self.max_response.hide()

        selected_step_dynamic_content = []
        for item in self.selected_step.items:
            if item['name'] == 'contentTypes':
                selected_step_dynamic_content = [ z in item['value'] for z in ['images', 'javaScript', 'css'] ]
        if self.selected_step.is_lead():
            self.step_dynamic_content.show()
            self.step_dynamic_content.set_values(*selected_step_dynamic_content)
        else:
            self.step_dynamic_content.hide()

        self.step_flow_target_plus.hide()
        self.step_flow_sleep.hide()
        self.step_flow_ddl_ddi.hide()
        self.step_flow_varloop_start.hide()
        self.step_flow_varloop_end.hide()
        self.step_flow_fixloop.hide()
        self.step_flow_conditional_true.hide()
        self.step_flow_conditional_false.hide()
        self.step_flow_response_table.hide()
        self.step_flow_percentage_table.hide()
        self.step_flow_conditional_table.hide()

        # need to update the step list every time because new steps might have been added after the initial import
        steps = self.uj.list_step_name_id_pairs()
        steps.update({'NEXT_STEP': 'Next Step', 'END_CYCLE': 'End Cycle', 'END_USER': '******'})
        self.step_flow_target_plus.reset_items(steps) # reset val even if hidden

        if not hasattr(self.selected_step, 'flow_type'):
            self.step_flow_control_type.set_text('GoTo')
            self.step_flow_target_plus.show()
            self.step_flow_target_plus.set_text('NEXT_STEP')
            self.step_flow_sleep.show()
            self.step_flow_sleep.set_text('0.0')
        else:                              # ==================================== ALL NON 'GOTO' FLOW CONTROL ====================================
            self.step_flow_control_type.set_text(self.selected_step.flow_type)

            selected_step_flow_target = ''
            selected_step_flow_sleep = ''
            selected_step_flow_ddi = ''
            selected_step_flow_miniter = ''
            selected_step_flow_maxiter = ''
            selected_step_flow_iter = ''
            selected_step_flow_conditional_true_target = ''
            selected_step_flow_conditional_false_target = ''
            for item in self.selected_step.flow_items:
                if item['name'] == 'DESTINATIONSTEP':
                    selected_step_flow_target = item['value']
                if item['name'] == 'SLEEPTIME':
                    selected_step_flow_sleep = str(float(item['value'])/1000)
                if item['name'] == 'DDITEM':
                    selected_step_flow_ddi = item['value']
                if item['name'] == 'MINITERCOUNT':
                    selected_step_flow_miniter = item['value']
                if item['name'] == 'MAXITERCOUNT':
                    selected_step_flow_maxiter = item['value']
                if item['name'] == 'ITERCOUNT':
                    selected_step_flow_iter = item['value']
                if item['name'] == 'TRUECONDITIONSTEP':
                    selected_step_flow_conditional_true_target = item['value']
                if item['name'] == 'FALSECONDITIONSTEP':
                    selected_step_flow_conditional_false_target = item['value']

            if self.selected_step.flow_type not in ['RESPONSE', 'CONDTITIONAL', 'PERCENTAGE']:
                self.step_flow_target_plus.show()
                self.step_flow_target_plus.set_text(selected_step_flow_target)

            if self.selected_step.flow_type not in ['RESPONSE', 'PERCENTAGE']:
                self.step_flow_sleep.show()
                self.step_flow_sleep.set_text(selected_step_flow_sleep)

            if self.selected_step.flow_type == 'DDLOOP':
                applicable_ddis_by_refresh = self.uj.find_ddis_by_attribute('lifecycle', 'T') # {'C': 'Cycle', 'R': 'Run', 'T': 'Time', 'U': 'User',}
                applicable_ddis_by_selection_randomunique = self.uj.find_ddis_by_attribute('selection_type', 'RANDONCE')
                applicable_ddis_by_selection_sequnique = self.uj.find_ddis_by_attribute('selection_type', 'SEQUONCE')
                applicable_ddis_by_selection = applicable_ddis_by_selection_randomunique + applicable_ddis_by_selection_sequnique
                applicable_ddis = { z.name:z.name for z in applicable_ddis_by_refresh if z in applicable_ddis_by_selection }
                if len(applicable_ddis):
                    self.step_flow_ddl_ddi.reset_items(applicable_ddis)
                    self.step_flow_ddl_ddi.set_text(selected_step_flow_ddi)
                self.step_flow_ddl_ddi.show()

            if self.selected_step.flow_type == 'VARIABLELOOP':
                self.step_flow_varloop_start.show()
                self.step_flow_varloop_end.show()
                self.step_flow_varloop_start.set_text(selected_step_flow_miniter)
                self.step_flow_varloop_end.set_text(selected_step_flow_maxiter)

            if self.selected_step.flow_type == 'FIXEDLOOP':
                self.step_flow_fixloop.show()
                self.step_flow_fixloop.set_text(selected_step_flow_iter)

            if self.selected_step.flow_type == 'RESPONSE':
                orders = list(set([ z['order'] for z in self.selected_step.flow_items]))
                orders.sort()
                if len(orders):
                    self.step_flow_response_table.show()
                    table = []
                    for order in orders:
                        destination = ''
                        match = ''
                        source = ''
                        sleep = ''
                        for item in self.selected_step.flow_items:
                            if item['name'] == 'DESTINATIONSTEP' and item['order'] == order:
                                try:
                                    destination = self.uj.find_step_by_id(int(item['value'])).name
                                except ValueError:
                                    if item['value'] == 'NEXT_STEP':
                                        destination = 'Next Step'
                                    elif item['value'] == 'END_CYCLE':
                                        destination = 'End Cycle'
                                    else:
                                        destination = 'End User'
                            if item['name'] == 'MATCHCRITERIA' and item['order'] == order:
                                match = item['value']
                            if item['name'] == 'RESPONSESTEP' and item['order'] == order:
                                source = self.uj.find_step_by_id(int(item['value'])).name
                            if item['name'] == 'SLEEPTIME' and item['order'] == order:
                                sleep = str(float(item['value'])/1000)

                        table.append([{source: self.uj.list_step_name_id_pairs()}, match, {destination: steps}, sleep])

                    self.step_flow_response_table.set_text(table)

            if self.selected_step.flow_type == 'PERCENTAGE':
                orders = list(set([ z['order'] for z in self.selected_step.flow_items]))
                orders.sort()
                if len(orders):
                    self.step_flow_percentage_table.show()
                    table = [['100', {'Next Step': ['Next Step']}, '0.0']]
                    extra_percentage = 0
                    for order in orders:
                        destination = ''
                        percentage = ''
                        sleep = ''
                        for item in self.selected_step.flow_items:
                            if item['name'] == 'DESTINATIONSTEP' and item['order'] == order:
                                destination = item['value']
                            if item['name'] == 'PERCENTAGE' and item['order'] == order:
                                percentage = item['value']
                                extra_percentage += int(percentage)
                            if item['name'] == 'SLEEPTIME' and item['order'] == order:
                                sleep = str(float(item['value'])/1000)

                        table.append([percentage, {destination: steps}, sleep])

                    table[0][0] = str(100 - extra_percentage)
                    self.step_flow_percentage_table.set_text(table)

            if self.selected_step.flow_type == 'CONDTITIONAL':

                self.step_flow_conditional_true.show()
                self.step_flow_conditional_true.reset_items(steps)
                self.step_flow_conditional_true.set_text(selected_step_flow_conditional_true_target)
                self.step_flow_conditional_false.show()
                self.step_flow_conditional_false.reset_items(steps)
                self.step_flow_conditional_false.set_text(selected_step_flow_conditional_false_target)

                orders = list(set([ z['order'] for z in self.selected_step.flow_items]))
                orders.sort()
                if len(orders):
                    self.step_flow_conditional_table.show()
                    table = []
                    for order in orders:
                        condition = ''
                        phrase1 = ''
                        operator = ''
                        phrase2 = ''
                        for item in self.selected_step.flow_items:
                            if item['name'] == 'CONDITION' and item['order'] == order:
                                conditions = {'less than': '<', 'less than or equals': '<=', 'equals': '=', 'not equals': '!=', 'greater than or equals': '>=', 'greater than': '>', 'contains': 'in', 'does not contain': 'not in',}
                                condition = conditions[item['value']]
                            if item['name'] == 'FIRSTPHRASE' and item['order'] == order:
                                phrase1 = item['value']
                            if item['name'] == 'OPERATOR' and item['order'] == order:
                                operator = item['value']
                            if item['name'] == 'SECONDPHRASE' and item['order'] == order:
                                phrase2 = item['value']

                        table.append([phrase1, {condition: ['<', '<=', '=', '=>', '>', '!=', 'in', 'not in']}, phrase2, {operator: ['AND', 'OR']}])

                    self.step_flow_conditional_table.set_text(table)
Ejemplo n.º 35
0
class PythonConsoleWidget(QWidget, MooseWidget):
    """
    Widget holding the input/output of a python console.

    Saves/restores history to preferences. This allows previous commands
    to be saved/restored.
    There is a global dict called "peacock" that allows saving arbitrary
    variables in.
    For example, peacock["your_variable"] could be any python variable.

    Signals:
        new_line: A new line of input. Argument is the input.
    """
    new_line = pyqtSignal(str)

    def __init__(self, **kwds):
        super(PythonConsoleWidget, self).__init__(**kwds)

        self.top_layout = WidgetUtils.addLayout(vertical=True)
        self.setLayout(self.top_layout)
        self.output = QPlainTextEdit(parent=self)
        self.output.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.output.setReadOnly(False)
        self.output.setFocusPolicy(Qt.ClickFocus)
        self.output.setStyleSheet("QPlainTextEdit { background: black; color: white;}")
        self.output.setTextInteractionFlags(Qt.TextSelectableByMouse|Qt.TextSelectableByKeyboard|Qt.LinksAccessibleByMouse|Qt.LinksAccessibleByKeyboard)
        self.top_layout.addWidget(self.output)

        self.input_layout = WidgetUtils.addLayout()
        self.top_layout.addLayout(self.input_layout)
        self.prompt = WidgetUtils.addLabel(self.input_layout, self, ">>>")

        self.input_line = WidgetUtils.addLineEdit(self.input_layout, self, self._returnPressed)
        self.input_line.setFocusPolicy(Qt.StrongFocus)
        self.input_line.installEventFilter(self)

        self.user_inputs = []
        self.current_index = -1
        # get a list of globals and locals from the callstack
        self._global_data = {}
        self._global_data['global_vars'] = globals()
        self._global_data['peacock'] = {}
        self.console = QPythonConsole(self._global_data, parent=self)
        self.console.write_output.connect(self.output.appendPlainText)
        self.output.appendPlainText("Peaock variables are in the dict 'peacock'")
        self.output.appendPlainText("Global variables are in the dict 'global_vars'")
        self.console.prompt_changed.connect(self.prompt.setText)
        self.new_line.connect(self.console._newLine)
        self.console._setPrompt()
        self._loadHistory()
        self.resize(600, 400)
        self.setup()

    def _loadHistory(self):
        """
        Loads previous commands from settings.
        """
        settings = QSettings()
        history = settings.value("python/history", type=str)
        if history != None:
            for v in history:
                self.user_inputs.append(str(v))
            self.current_index = len(self.user_inputs)

    def eventFilter(self, obj, event):
        """
        Process QEvent
        Input:
            obj: The object that the event happened on
            event: QEvent() object
        Return:
            True if we processed this event. False otherwise.
        """
        if obj == self.input_line:
            if event.type() == QEvent.KeyPress:
                if event.key() == Qt.Key_Up:
                    self._changeInput(-1)
                    return True
                elif event.key() == Qt.Key_Down:
                    self._changeInput(1)
                    return True
                elif event.key() == Qt.Key_Tab:
                    # don't allow to tab out of the command line
                    return True
        return False

    def saveHistory(self):
        """
        Save history into settings.
        """
        settings = QSettings()
        num_to_save = settings.value("python/history_size", type=int)
        if num_to_save == None:
            num_to_save = 50
            settings.setValue("python/history_size", num_to_save)

        settings.setValue("python/history", self.user_inputs[-num_to_save:])

    def _changeInput(self, change):
        """
        Looks through the history and changes the input line.
        Input:
            change: int that specifies where in the list to change to
        """
        self.current_index += change
        if self.current_index < 0:
            self.current_index = 0
        elif self.current_index >= len(self.user_inputs):
            self.current_index = len(self.user_inputs)
        if self.current_index >= 0 and self.current_index < len(self.user_inputs):
            self.input_line.setText(self.user_inputs[self.current_index ])

    def setVariable(self, name, value):
        """
        Put a variable into the global dict "peacock".
        Input:
            name: key value of the "peacock" dict
            value: The value
        """
        self._global_data["peacock"][name] = value

    @pyqtSlot()
    def _returnPressed(self):
        """
        The user pressed return so process the input line
        """
        text = unicode(self.input_line.text())
        self.input_line.setText("")
        self.new_line.emit(text)
        if text:
            self.user_inputs.append(text)
        self.current_index = len(self.user_inputs)
Ejemplo n.º 36
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)
Ejemplo n.º 37
0
class View(QWidget):

    send_data           = pyqtSignal(object)
    baudrate_src_changed    = pyqtSignal(object)
    baudrate_pump_changed    = pyqtSignal(object)
    baudrate_temp_changed    = pyqtSignal(object)
    #eol_changed         = pyqtSignal(object)
    port_changed        = pyqtSignal(object)
    seedPulseChanged = pyqtSignal(object)
    seedFreValueChanged = pyqtSignal(object)
    seedPulseFreChanged = pyqtSignal(object)
    firstPumpChanged = pyqtSignal(object)
    secondPumpChanged = pyqtSignal(object)
    startSrcModel = pyqtSignal(object)
    startPumpModel = pyqtSignal(object)
    startTempModel = pyqtSignal(object)
    beginTime = pyqtSignal(object)
    emitUsername = pyqtSignal(object)

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


        self.queue      = Queue()
        self.end_cmd    = None
        self.autoscroll = True
        self.msg_sent   = False

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_gui)
        self.timer.start(100)
        self.srcModelstarted = False
        self.pumpModelstarted = False
        self.tempModelstarted = False
        self.currentValueList =list()
        self.currentTimeList = list()
        self.buttonMinimumWidth = 100
        # self.topSeedCurrent = 700
        # self.topPumpCurrent = 1000
        self.canClosePort = True

        self.initSeedPulse = 0
        self.initSeedFre = 0
        self.init1stCurrent = 0
        self.init2stCurrent = 0
        self.initSeedCurrent =0
        # get the lastsave record
        self.last = LastLog()
        self.lastpick = self.last.loadLast()
        uslast = self.lastpick.get('user',False)
        print('uslast',uslast)
        if uslast is False:
            self.user = User()
        else:
            self.user = uslast
        #init down machine status
        self.__init__slaveStatus()
        self.__initUI()


    def __init__slaveStatus(self):
        self.isSeedOpen = False
        self.seedcurrentre = False
        self.seedpulsere = False
        self.seedfrequecere = False
        self.seedcurrent = 0
        self.seedpulse = 0
        self.seedfrequece = 0
        self.firstcurrent = 0
        self.secondcurrent = 0
        self.isFirstPumpOpen = False
        self.isSecondPumpOpen = False
        self.isLEDOpen = False


    def __initUI(self):
        '''main window box'''

        self.mainBox = QVBoxLayout(self)#使用垂直布局类
        self.showBox = QHBoxLayout()
        self.setWindowState(Qt.WindowMaximized)
###
#command area: push button, plain text edit and line edit
###
        cmd_btn = QPushButton('Send Command (ctrl+Q)')
        cmd_btn.setMinimumWidth(self.buttonMinimumWidth)
        cmd_btn.clicked.connect(self.emit_send_data)
        #import cmd strl+enter
        cmdEnterAction = QAction(self)
        cmdEnterAction.setShortcut('ctrl+Q')
        cmdEnterAction.setStatusTip(' press ctrl+Q to send command')
        cmdEnterAction.triggered.connect(self.emit_send_data)
        self.cmd_edit = QLineEdit()
        self.cmd_edit.addAction(cmdEnterAction)
        cmdBox = QVBoxLayout()


#message box
        self.editer = QPlainTextEdit()
        self.editer.setReadOnly(True)
# <<<<<<< HEAD
        self.editer.setMaximumSize(300,2000)
# =======
        cmdBox = QVBoxLayout()
        # cmdBox.addWidget(self.cmd_edit)
        # cmdBox.addWidget(cmd_btn)
        self.powerShow = PowerShow()
        cmdBox.addWidget(self.powerShow)
# >>>>>>> a45e80ec77a4a8729fa4205165faae001fd09cab
        cmdBox.addWidget(self.editer)
        # cmd_btn.setMaximumSize(300,400)
        # self.cmd_edit.setMaximumSize(300,100)

###
#paint area use matplotlib
###
        self.paintwidget = QWidget(self)
        self.painter = MyDynamicMplCanvas(self.paintwidget, width=5, height=4, dpi=100)
        # self.showBox.addLayout(self.powerShowUI())
        self.showBox.addLayout(cmdBox)
        self.showBox.addWidget(self.painter)
        self.toolBoxUI()
        self.mainBox.addWidget(self.toolBox)
        self.mainBox.addLayout(self.showBox)


        self.setLayout(self.mainBox)
        self.setWindowTitle("光子暗化平台软件")

    def toolBoxUI(self):
        '''use a tab widget to organize set area
        '''
###
#QTabWidget() layout
###
        gbox1 = QGroupBox()
        gbox1.setStyleSheet("QGroupBox{border:None;}")
        self.useBox = QHBoxLayout(gbox1)
        self.useBox.setGeometry(QRect( 0, 0, 300,100))
        gbox2 = QGroupBox()
        gbox2.setStyleSheet("QGroupBox{border:None;}")
        self.portUI = PortGBUI()
        self.portUI.setupUi(gbox2)
        # self.portUI.widget.setGeometry(QRect( 0, 0, 450,200))
        gbox3 = QGroupBox()
        gbox3.setStyleSheet("QGroupBox{border:None;}")
        self.pumpUI = PumpUI()
        self.pumpUI.setupUi(gbox3)
        self.pumpUI.groupBox.setTitle(' ')
        # self.pumpUI.widget.setGeometry(QRect( 0, 0, 400,200))
        gbox4 = QGroupBox()
        gbox4.setStyleSheet("QGroupBox{border:None;}")
        gbox5 = QGroupBox()
        gbox5.setStyleSheet("QGroupBox{border:None;}")
        #self.menuBox = QHBoxLayout()

        # self.setBox = QHBoxLayout(gbox2)
        self.pumpBox = QGridLayout(gbox3)
        self.powerRecordBox = QHBoxLayout(gbox4)
        self.toolBox = QTabWidget()
        # self.toolBox.setStyleSheet("QTabWidget.pane{background: transparent;}\
        #     ")
        self.toolBox.addTab(gbox1,'用户登录')
        self.toolBox.addTab(gbox2,'串口设置')
        self.toolBox.addTab(gbox3,'泵浦开关')
        self.toolBox.addTab(gbox4,'功率计')
        self.toolBox.addTab(gbox5,'帮助')
        # self.toolBox.
        self.toolBox.setTabEnabled(1,False)
        self.toolBox.setTabEnabled(2,False)
        self.toolBox.setTabEnabled(3,False)
        self.toolBox.setMaximumSize(10000,200)
        # self.toolBox.resize(1200,200)
        userbox = UserView()
        userbox.usersignal.connect(self.setUser)
        self.useBox.addWidget(userbox)
        # self.useBox.addStretch()
        self.powerRecord = PowerRecord()
        self.powerRecord.getNowFig(self.painter)
        self.powerRecord.timeStateSignal.connect(self.painter.getLogTimeState)
        self.powerRecord.logStateSignal.connect(self.painter.getStartLog)
        self.powerRecord.plotlist.connect(self.painter.XYaxitList)
        self.powerRecordBox.addWidget(self.powerRecord)
#
#port set
#
        menuItem = ['300 baud','1200 baud',
            '2400 baud','4800 baud','9600 baud',
            '19200 baud','38400 baud','57600 baud',
            '115200 baud','230400 baud','250000 baud']
        self.portUI.baundrateSource.addItems(menuItem)
        self.portUI.baundratePump.addItems(menuItem)
        # self.portUI.baundrateTemp.addItems(menuItem)
#source port set
        #source
        portItem = ['com1','com2','com3','com4',
            'com5','com6','com7','com8','com9',
            'com10','com11','com12','com13',
            'com14','com15','com16','com17',
            'com18','com19','com20']
        self.portUI.portSource.addItems(portItem)
        self.portUI.portPump.addItems(portItem)
        self.setPortButton = self.portUI.openportSource
        self.closePortButton = self.portUI.closeportSource
        self.baundrateMenu = self.portUI.baundrateSource
        self.portEdit = self.portUI.portSource
        self.baundrateMenu.currentIndexChanged.connect(self.emit_br_src_changed)
        baudindex = self.lastpick.get('srcBaud',False)
        if baudindex is not False :
            self.baundrateMenu.setCurrentIndex(baudindex)
        else:
            self.baundrateMenu.setCurrentIndex(4)
        portindex = self.lastpick.get('srcPort',False)
        if baudindex is not False :
            self.portEdit.setCurrentIndex(portindex)
        else:
            self.portEdit.setCurrentIndex(1)

        baudindex = self.lastpick.get('pumpBaud',False)
        if baudindex is not False :
            self.portUI.baundratePump.setCurrentIndex(baudindex)
        else:
            self.portUI.baundratePump.setCurrentIndex(4)
        portindex = self.lastpick.get('pumpPort',False)
        if baudindex is not False :
            self.portUI.portPump.setCurrentIndex(portindex)
        else:
            self.portUI.portPump.setCurrentIndex(2)

###
#pump set
###
        self.openSeedButton = self.pumpUI.sourceSet
        self.setSeedPulse = self.pumpUI.pulseSpin
        self.openSeedButton.clicked.connect(self.emitSeedPulseAndFre)
        self.setSeedPulse.setValue(self.initSeedPulse)
        self.setSeedFreValue = self.pumpUI.frequencySpin
        self.setSeedCurrent = self.pumpUI.currentSpin
        self.setSeedCurrent.setValue(self.initSeedCurrent)
        self.openAll = self.pumpUI.sourceOpen
        self.sendfirst = self.pumpUI.firstPumpSet
        self.sendfirst.clicked.connect(self.emitFirstPumpCurrent)
        self.sendsecond = self.pumpUI.secondPumpSet
        self.sendsecond.clicked.connect(self.emitSecondPumpCurrent)
        self.setFirstpump = self.pumpUI.firstpumpSpin
        self.setFirstpump.setValue(self.init1stCurrent)
        self.setSecondpump = self.pumpUI.secondpumpSpin
        self.setSecondpump.setValue(self.init2stCurrent)
        self.closeAll = self.pumpUI.sourceClose
        self.pumpUI.firstpumpSpin.setMaximum(1000)
        self.pumpUI.secondpumpSpin.setMaximum(10000)
        self.pumpUI.secondpumpSpin.setSingleStep(500)




    def enableClosePort(self):
        if self.setSeedPulse.text()[:-2] > self.initSeedPulse :
            self.canClosePort = False
        print(self.canClosePort)
        if self.setSeedFreValue.texttext()[:-3] > self.initSeedFre :
            self.canClosePort = False
        print(self.canClosePort)
        if self.setSeedCurrent.text()[:-2] > self.initSeedCurrent:
            self.canClosePort = False
        print(self.canClosePort)
        if self.setFirstpump.text()[:-2] > self.init1stCurrent :
            self.canClosePort = False
        print(self.canClosePort)
        if self.setSecondpump.text()[:-2] > self.init2stCurrent :
            self.canClosePort = False
        print(self.canClosePort)

    def seedSignalSet(self, seedcurrent, seedpulse, seedfrequece):
        self.seedcurrent = seedcurrent
        self.setSeedCurrent.setValue(self.seedcurrent)
        self.seedpulse = seedpulse
        self.setSeedPulse.setValue(self.seedpulse)
        self.seedfrequece = seedfrequece
        self.setSeedFreValue.setValue(self.seedfrequece)

    def firstCurrentSet(self,value):
        self.firstcurrent = value
        self.setFirstpump.setValue(self.firstcurrent)

    def secondCurrentSet(self,value):
        self.secondcurrent = value
        self.setSecondpump.setValue(self.secondcurrent)

#==============================================================================
# Get, set
#==============================================================================

    def setPowerShowList(self,lst):
        self.powerShow.powerList = lst
        self.powerShow.updateFigure()

    def set_queue(self, queue):
        self.queue = queue

    def set_end_cmd(self, end_cmd):
        self.end_cmd = end_cmd

    # def set_autoscroll(self, value):
    #     self.autoscroll = value

    def set_port(self, value):
        self.portEdit.clear()
        self.portEdit.insert(value)

    def getSrcPort(self):
        self.lastpick['srcPort'] = self.portEdit.currentIndex()
        return self.portEdit.currentText()

    def getSrcBaudrate(self):
        self.lastpick['srcBaud'] = self.baundrateMenu.currentIndex()
        return self.baundrateMenu.currentText()[:-5]

    def getPumpPort(self):
        self.lastpick['pumpPort'] = self.portUI.portPump.currentIndex()
        return self.portUI.portPump.currentText()

    def getPumpBaudrate(self):
        self.lastpick['pumpBaud'] = self.portUI.baundratePump.currentIndex()
        return self.portUI.baundratePump.currentText()[:-5]

    def get_cmd(self):
        return self.cmd_edit.text()


    def setCurrentValue(self, currentValue,timeValue):
        if currentValue is not None:
            self.currentValueList = currentValue
            self.currentTimeList = timeValue


    def Button2Plot(self):
        self.painter.update_figure()

    def closeEvent(self, event):
        self.last.saveLast(self.lastpick)
        self.end_cmd()
        QWidget.closeEvent(self, event)
        print('exit')

    def beginGui(self):
        self.update()

    def update_gui(self):
        self.process_incoming()
        self.update()

    def updataFigure(self,newtime,power):
        # self.setCurrentValue(currentValue, timeValue)
        self.painter.XYaxit(newtime,power)
        self.painter.update_figure()

        # print('update?')
        # self.update()

    def process_incoming(self):
        while self.queue.qsize():
            try:
                msg = self.queue.get(0)
                self.editer.appendPlainText(str(msg))
                #show to the textplain?
                #if self.autoscroll:
                self.editer.ensureCursorVisible()
                self.scroll_down()
            except Queue.empty:
                print('=== empty queue ===')

    def scroll_down(self):
        sb = self.editer.verticalScrollBar()
        sb.setValue(sb.maximum())


    def changePort(self):
        if not self.msg_sent:
            self.msg_sent = True
            self.emit_port_changed()
        else:
            self.msg_sent = False
            return None

#==============================================================================
# Signals
#==============================================================================

    def emit_send_data(self):
        self.send_data.emit(self.get_cmd())
        self.cmd_edit.clear()

    def emit_send_command(self,command):
        self.send_data.emit(command)
        self.cmd_edit.clear()

    def emit_br_src_changed(self, value):
        baudrate = self.baundrateMenu.itemText(value)[:-5]
        self.baudrate_src_changed.emit(baudrate)

    def emit_br_pump_changed(self, value):
        baudrate = self.baundrateMenu.itemText(value)[:-5]
        self.baudrate_pump_changed.emit(baudrate)

    # def emit_br_temp_changed(self, value):
    #     baudrate = self.baundrateMenu.itemText(value)[:-5]
    #     self.baudrate_temp_changed.emit(baudrate)

    def emit_port_changed(self):
        self.port_changed.emit(self.portEdit.text())
        self.portEdit.clear()

    def emitWriteSeedPulse(self):
        self.seedPulseChanged.emit(self.setSeedPulse.text()[:-2])

    def emitWriteSeedFre(self):
        self.seedFreValueChanged.emit(self.setSeedFreValue.text()[:-3])

    def emitFirstPumpCurrent(self):
        self.firstPumpChanged.emit(self.setFirstpump.text()[:-2])

    def emitSecondPumpCurrent(self):
        self.secondPumpChanged.emit(self.setSecondpump.text()[:-2])

    def emitSeedPulseAndFre(self):
        seedPulseAndFre = [self.setSeedPulse.text()[:-2],
            self.setSeedFreValue.text()[:-3],self.setSeedCurrent.text()[:-2]]
        # print(self.setSeedPulse.text()[:-2],
        #     self.setSeedFreValue.text()[:-2],self.setSeedCurrent.text()[:-2])
        self.seedPulseFreChanged.emit(seedPulseAndFre)

    def setUser(self,value):
        self.user = value
        if value.getName() is not False:
            self.toolBox.setTabEnabled(1,True)
            self.toolBox.setTabEnabled(2,True)
            self.toolBox.setTabEnabled(3,True)
            self.powerRecord.setUserID(self.user.getName())
            self.startSrcModel.emit(self.srcModelstarted)
            self.srcModelstarted = True
            self.startPumpModel.emit(self.pumpModelstarted)
            self.pumpModelstarted = True
            # self.startTempModel.emit(self.tempModelstarted)
            # self.tempModelstarted = True
            self.emitUsername.emit(self.user.getName())
            print('emit username:'******'NoneUser')
        print('use in view:',self.user.getName())

    def lastLogSave(self):
        self.last.saveLast(self.lastpick)
Ejemplo n.º 38
0
class View(QWidget):

    # Send data to port
    send_data           = pyqtSignal(object)
    # Chage baudrate
    baudrate_changed    = pyqtSignal(object)
    # Change end of line
    eol_changed         = pyqtSignal(object)
    # Change port
    port_changed        = pyqtSignal(object)
    # Pause model
    pause_m             = pyqtSignal(object)
    # Continue model
    start_m             = pyqtSignal(object)

    def __init__(self):
        QWidget.__init__(self)

        self.queue      = None
        self.end_cmd    = None
        self.autoscroll = False
        self.msg_sent   = False

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_gui)
        self.timer.start(100)
                
        self.__initUI()

    def __initUI(self):
        vbox = QVBoxLayout(self)

        # Command box
        cmd_hbox = QHBoxLayout()

        self.cmd_edit = QLineEdit()
        cmd_hbox.addWidget(self.cmd_edit)

        cmd_btn = QPushButton('Send')
        cmd_btn.clicked.connect(self.emit_send_data)
        cmd_hbox.addWidget(cmd_btn)

        cmd_btn = QPushButton('Start')
        cmd_btn.clicked.connect(self.start_m.emit)
        cmd_hbox.addWidget(cmd_btn)

        cmd_btn = QPushButton('Stop')
        cmd_btn.clicked.connect(self.pause_m.emit)
        cmd_hbox.addWidget(cmd_btn)

        vbox.addLayout(cmd_hbox)

        # Text edit area
        self.editer = QPlainTextEdit()
        self.editer.scrollContentsBy = self.ModScrollContentsBy
        vbox.addWidget(self.editer)

        # Settings area
        stng_hbox = QHBoxLayout()

        # - Autoscroll
        chk_btn = QCheckBox('Autoscroll')
        chk_btn.stateChanged.connect(self.set_autoscroll)
        stng_hbox.addWidget(chk_btn)

        cmd_btn = QPushButton('Clear')
        cmd_btn.clicked.connect(self.editer.clear)
        stng_hbox.addWidget(cmd_btn)

        stng_hbox.addStretch(1)

        # - Ending of line
        self.eol_menu = QComboBox()
        self.eol_menu.addItem('No line ending')
        self.eol_menu.addItem('Newline')
        self.eol_menu.addItem('Carriage return')
        self.eol_menu.addItem('Both NL + CR')
        self.eol_menu.setCurrentIndex(0)
        self.eol_menu.currentIndexChanged.connect(self.emit_eol_changed)
        stng_hbox.addWidget(self.eol_menu)

        # - Baudrate select
        self.br_menu = QComboBox()
        self.br_menu.addItem('300 baud')
        self.br_menu.addItem('1200 baud')
        self.br_menu.addItem('2400 baud')
        self.br_menu.addItem('4800 baud')
        self.br_menu.addItem('9600 baud')
        self.br_menu.addItem('19200 baud')
        self.br_menu.addItem('38400 baud')
        self.br_menu.addItem('57600 baud')
        self.br_menu.addItem('115200 baud')
        self.br_menu.addItem('230400 baud')
        self.br_menu.addItem('460800 baud')
        self.br_menu.currentIndexChanged.connect(self.emit_br_changed)
        # Set default baudrate 9600
        self.br_menu.setCurrentIndex(4)

        stng_hbox.addWidget(self.br_menu)

        vbox.addLayout(stng_hbox)

        port_hbox = QHBoxLayout()
        port_lbl = QLabel('Port: ')
        port_hbox.addWidget(port_lbl)

        self.port_edit = QLineEdit()

        self.port_edit.editingFinished.connect(self.changePort)
        port_hbox.addWidget(self.port_edit)

        vbox.addLayout(port_hbox)

        self.setLayout(vbox)

    def show_error(self, value):
        msg = QMessageBox(
                QMessageBox.NoIcon, 'Error occured.', value, QMessageBox.Ok)
        msg.exec()

#==============================================================================
# Get, set
#==============================================================================

    def set_queue(self, queue):
        self.queue = queue

    def set_end_cmd(self, end_cmd):
        self.end_cmd = end_cmd

    def set_autoscroll(self, value):
        print('Set autoscroll: {}.'.format(value))
        self.autoscroll = value

    def set_port(self, value):
        self.port_edit.insert(value)

    def get_cmd(self):
        return self.cmd_edit.text()

    def set_eol(self, value):
        self.eol_menu.setCurrentIndex(value)

    def closeEvent(self, event):
        self.end_cmd()
        QWidget.closeEvent(self, event)
        print('exit')

    def update_gui(self):
        self.process_incoming()
        self.update()

    def process_incoming(self):
        while self.queue.qsize():
            try:
                msg = self.queue.get(0)
                # Check contents of message and do what it says
                # As a test, we simply print it
                print(str(msg))
                self.editer.appendPlainText(str(msg))
                if self.autoscroll:
                    self.editer.ensureCursorVisible()
                    self.scroll_down()
            except Queue.empty:
                pass

    def scroll_down(self):
        sb = self.editer.verticalScrollBar()
        sb.setValue(sb.maximum())
        self.editer.moveCursor(QTextCursor.End)

    def changePort(self):
        if not self.msg_sent:
            self.msg_sent = True
            self.emit_port_changed()
        else:
            self.msg_sent = False
            return None

#==============================================================================
# Signals
#==============================================================================

    def emit_send_data(self):
        self.send_data.emit(self.get_cmd())
        self.cmd_edit.clear()

    def emit_br_changed(self, value):
        baudrate = self.br_menu.itemText(value)[:-5]
        self.baudrate_changed.emit(baudrate)

    def emit_eol_changed(self, value):
        self.eol_changed.emit(value)

    def emit_port_changed(self):
        self.port_edit.clearFocus()
        self.port_changed.emit(self.port_edit.text())

#==============================================================================
# Events
#==============================================================================
    def ModScrollContentsBy(self, dx, dy):
        if self.autoscroll:
            self.editer.ensureCursorVisible()
        else:
            QPlainTextEdit.scrollContentsBy(self.editer, dx, dy)
Ejemplo n.º 39
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()