Beispiel #1
0
class Window(QWidget):

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

        self.title = "PyQt ButtonGroup"
        self.top = 100
        self.left = 100
        self.width = 400
        self.height = 300

        self.buttongroup = QButtonGroup()
        self.hbox = QHBoxLayout()
        self.label = QLabel(self)

        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon("home.png"))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        #self.buttongroup.buttonClicked[int].connect(self.onButtonClicked)
        self.buttongroup.buttonPressed[int].connect(self.onButtonPressed)
        self.buttongroup.buttonReleased[int].connect(self.onButtonReleased)
        self.buttonGroup()
        self.hbox.addWidget(self.label)
        self.setLayout(self.hbox)

        self.show()

    def buttonGroup(self):
        button = QPushButton('Python')
        self.buttongroup.addButton(button, 1)
        self.hbox.addWidget(button)

        button2 = QPushButton('Java')
        self.buttongroup.addButton(button2, 2)
        self.hbox.addWidget(button2)

        button3 = QPushButton('C++')
        self.buttongroup.addButton(button3, 3)
        self.hbox.addWidget(button3)

    def onButtonClicked(self, id):
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + ' was clicked')

    def onButtonPressed(self, id):
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + ' was pressed!')

    def onButtonReleased(self, id):
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + ' was released!')
Beispiel #2
0
class LocalButtonsConf(OptionsDialogGroupBox):
    def __init__(self, name, main):
        self.main = main
        OptionsDialogGroupBox.__init__(self, name, main)
        self.buttonBox = QGroupBox("Pins")
        self.buttonBoxLayout = QVBoxLayout()
        self.buttonBox.setLayout(self.buttonBoxLayout)

    def initUI(self):
        vbox = QVBoxLayout()
        self.polBox = QCheckBox("Invert")
        vbox.addWidget(self.polBox)
        self.buttongroup = QButtonGroup()
        self.buttongroup.setExclusive(False)
        vbox.addWidget(self.buttonBox)

        self.setLayout(vbox)

    def initButtons(self, num):
        #delete buttons
        self.num = num

        # Remove buttons
        for i in range(self.buttonBoxLayout.count()):
            b = self.buttonBoxLayout.takeAt(0)
            self.buttonBoxLayout.removeItem(b)
            b.widget().deleteLater()
        for b in self.buttongroup.buttons():
            self.buttongroup.removeButton(b)

        self.buttonBox.update()

        for i in range(self.num):
            cb = QCheckBox(str(i + 1))
            self.buttongroup.addButton(cb, i)
            self.buttonBoxLayout.addWidget(cb)

        def localcb(mask):
            for i in range(self.num):
                self.buttongroup.button(i).setChecked(mask & (1 << i))

        self.main.comms.serialGetAsync("local_btnmask?", localcb, int)

    def apply(self):
        mask = 0
        for i in range(self.num):
            if (self.buttongroup.button(i).isChecked()):
                mask |= 1 << i
        self.main.comms.serialWrite("local_btnmask=" + str(mask))
        self.main.comms.serialWrite("local_btnpol=" +
                                    ("1" if self.polBox.isChecked() else "0"))

    def readValues(self):
        self.main.comms.serialGetAsync("local_btnpins?", self.initButtons, int)

        self.main.comms.serialGetAsync("local_btnpol?", self.polBox.setChecked,
                                       int)
Beispiel #3
0
class PaletteList(QListWidget):
    def __init__(self, window=None):
        super(PaletteList, self).__init__(window)
        self.window = window
        self.uniformItemSizes = True

        self.list = []
        self.current_index = 0
        self.radio_button_group = QButtonGroup()

    def add_palette_from_image(self, image_filename, image_map):
        print(image_filename)
        item = QListWidgetItem(self)
        self.addItem(item)
        pf = PaletteFrame(len(self.list), image_filename, image_map, self)
        self.list.append(pf)
        item.setSizeHint(pf.minimumSizeHint())
        self.setItemWidget(item, pf)
        # Try and make it the right size
        self.setMinimumWidth(self.sizeHintForColumn(0))
        return pf

    def remove_last_palette(self):
        print('Removing last palette!')
        self.takeItem(len(self.list) - 1)
        self.list.pop()

    def duplicate(self, idx):
        command = CommandDuplicate(self, idx, "Duplicate Palette %d" % idx)
        self.window.undo_stack.push(command)

    def set_current_palette(self, idx):
        self.current_index = idx
        self.radio_button_group.button(idx).setChecked(True)
        self.window.palette_text.setText(self.get_current_palette().name)
        self.window.update_view()

    def get_current_palette(self):
        return self.list[self.current_index]

    def get_last_palette(self):
        return self.list[-1]

    def get_palette(self, idx):
        return self.list[idx]

    def clear(self):
        print('PaletteList clear')
        # Need to remove things in reverse order, duh
        for idx, l in reversed(list(enumerate(self.list))):
            print(idx)
            self.takeItem(idx)
            l.deleteLater()
        self.list = []
        self.current_index = 0
Beispiel #4
0
class RecordWindow(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Рекорды")
        self.setFixedSize(400, 300)
        self.init_ui()

    def init_ui(self):
        font = QFont()
        font.setPointSize(12)

        self.tableWidget = QTableWidget(self)
        self.tableWidget.setGeometry(QtCore.QRect(140, 0, 260, 300))
        self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setRowCount(0)

        self.buttonGroup = QButtonGroup(self)
        for n, text in enumerate(['Новичок', 'Эксперт', 'Бывалый']):
            rb = QRadioButton(self)
            rb.setGeometry(QtCore.QRect(30, 100 + 30 * n, 91, 17))
            rb.setText(text)
            rb.setFont(font)
            self.buttonGroup.addButton(rb)
            self.buttonGroup.setId(rb, n)

        self.buttonGroup.buttonClicked.connect(self.choose_table)

        self.tableWidget.setHorizontalHeaderLabels(["Имя", "Время"])
        self.tableWidget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

        self.game_stat = GameStat()
        self.buttonGroup.button(0).click()

    def choose_table(self):
        res = self.game_stat.get_records(self.sender().checkedButton().text())
        self.tableWidget.setRowCount(len(res))
        for i in range(len(res)):
            name = QTableWidgetItem(res[i]["name"])
            name.setTextAlignment(QtCore.Qt.AlignCenter)
            time = QTableWidgetItem(str(res[i]["time"]))
            time.setTextAlignment(QtCore.Qt.AlignCenter)
            self.tableWidget.setItem(i, 0, name)
            self.tableWidget.setItem(i, 1, time)

        # self.tableWidget.resizeColumnsToContents()

    def show(self):
        self.exec()
Beispiel #5
0
class RadioButtons(WidgetBridge, Choices):
    _qttype = QGroupBox

    def customize(self, widget):
        assert self.choices, "RadioButtons: Cannot build widget bridge without choices"
        # We give the GroupBox a container so we can add stretch at the end.
        self.container = QWidget(self.parent)
        hbox = QHBoxLayout(self.container)
        self.buttongroup = QButtonGroup(self.parent)
        if "direction" in self.config and \
                self.config["direction"].lower() == "vertical":
            box = QVBoxLayout()
        else:
            box = QHBoxLayout()
        ix = 1
        for text in self.choicesdict().values():
            rb = QRadioButton(text, self.parent)
            box.addWidget(rb)
            self.buttongroup.addButton(rb, ix)
            ix += 1
        widget.setLayout(box)
        hbox.addWidget(widget)
        hbox.addStretch(1)
        hbox.setContentsMargins(QMargins(0, 0, 0, 0))

    def apply(self, value):
        for b in self.buttongroup.buttons():
            b.setChecked(False)
        b = self.buttongroup.button(self.index(value) + 1)
        if b:
            b.setChecked(True)

    def retrieve(self):
        ix = self.buttongroup.checkedId()
        return self.at(ix - 1) if ix > 0 else None
Beispiel #6
0
class ButtonGroup(QWidget):
    def __init__(self):
        super().__init__()

        self.grid = QGridLayout()
        self.btn_group = QButtonGroup()
        self.initUI()

    def initUI(self):
        pos = [(x, y) for x in range(3) for y in range(3)]
        btn_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
        for pos, num in zip(pos, btn_list):
            btn = QPushButton(num)
            self.grid.addWidget(btn, *pos)
            self.btn_group.addButton(btn, int(num))

        self.btn_group.buttonClicked[int].connect(self.button_group_clicked)
        self.setLayout(self.grid)
        self.setWindowTitle("Button Group")
        self.resize(400, 250)
        self.center()
        self.show()

    def button_group_clicked(self, id):
        btn = self.btn_group.button(id)
        btn.setText(str(randint(1, 100)))

    def center(self):
        geom = self.frameGeometry()
        cnt = QDesktopWidget().availableGeometry().center()
        geom.moveCenter(cnt)
        self.move(geom.topLeft())
Beispiel #7
0
class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.title = "PyQt5 QButton Group"
        self.top = 200
        self.left = 500
        self.width = 400
        self.height = 300

        self.setWindowTitle(self.title)
        self.setWindowIcon(QtGui.QIcon("icon.png"))
        self.setGeometry(self.left, self.top, self.width, self.height)

        hbox = QHBoxLayout()

        self.label = QLabel(self)
        self.label.setFont(QtGui.QFont("Sanserif", 15))
        hbox.addWidget(self.label)

        self.buttongroup = QButtonGroup()
        #self.buttongroup.setExclusive(False)
        self.buttongroup.buttonClicked[int].connect(self.on_button_clicked)

        button = QPushButton("Python")

        self.buttongroup.addButton(button, 0)
        button.setFont(QtGui.QFont("Sanserif", 15))
        button.setIcon(QtGui.QIcon("pythonicon.png"))
        button.setIconSize(QtCore.QSize(40, 40))
        hbox.addWidget(button)

        button = QPushButton("Java")
        self.buttongroup.addButton(button, 1)
        button.setFont(QtGui.QFont("Sanserif", 15))
        button.setIcon(QtGui.QIcon("java.png"))
        button.setIconSize(QtCore.QSize(40, 40))
        hbox.addWidget(button)

        button = QPushButton("C++")
        self.buttongroup.addButton(button, 2)
        button.setFont(QtGui.QFont("Sanserif", 15))
        button.setIcon(QtGui.QIcon("cpp.png"))
        button.setIconSize(QtCore.QSize(40, 40))
        hbox.addWidget(button)

        self.setLayout(hbox)
        self.show()

    def on_button_clicked(self, id):
        print(id)
        for button in self.buttongroup.buttons():
            print(type(button))
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + " Was Clicked ")
                self.setWindowTitle("andy")
                button.setIconSize(QtCore.QSize(60, 60))
                print(button.text())
                button.setText("andy")
Beispiel #8
0
class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'Button Group'
        self.top = 200
        self.left = 400
        self.width = 400
        self.height = 200
        self.initWindow()

    def initWindow(self):
        self.setWindowTitle(self.title)
        self.setWindowIcon(QtGui.QIcon('avatar.png'))
        self.setGeometry(self.left, self.top, self.width, self.height)

        vbox = QVBoxLayout()
        hbox = QHBoxLayout()
        self.label = QLabel('This is label', self)
        self.label.setFont(QtGui.QFont('Sanserif', 13))
        vbox.addWidget(self.label)

        self.buttongroup = QButtonGroup()
        self.buttongroup.buttonClicked[int].connect(self.on_button_clicked)

        button = QPushButton('Python')
        self.buttongroup.addButton(button, 1)
        self.buttongroup.addButton(button, 1)
        button.setFont(QtGui.QFont("Sanserif", 13))
        button.setIcon(QtGui.QIcon("avatar.png"))
        button.setIconSize(QtCore.QSize(15, 15))
        hbox.addWidget(button)

        button = QPushButton("Java")
        self.buttongroup.addButton(button, 2)
        button.setFont(QtGui.QFont("Sanserif", 13))
        button.setIcon(QtGui.QIcon("avatar.png"))
        button.setIconSize(QtCore.QSize(15, 15))
        hbox.addWidget(button)

        button = QPushButton("C++")
        self.buttongroup.addButton(button, 3)
        button.setFont(QtGui.QFont("Sanserif", 13))
        button.setIcon(QtGui.QIcon("avatar.png"))
        button.setIconSize(QtCore.QSize(15, 15))
        hbox.addWidget(button)
        vbox.addLayout(hbox)
        self.setLayout(vbox)
        self.show()

    def on_button_clicked(self, id):
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + ' Was Clicked')
class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.title = "PyQt5 QButton Group"
        self.left = 500
        self.top = 200
        self.width = 300
        self.height = 250
        self.iconName = "icon.png"
        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon(self.iconName))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        hqbox = QHBoxLayout()

        self.buttongroup = QButtonGroup()
        self.buttongroup.buttonClicked[int].connect(self.on_button_clicked)

        self.label = QLabel(self)
        self.label.setFont(QtGui.QFont("Sanserif", 14))
        hqbox.addWidget(self.label)

        button = QPushButton("Python")
        button.setFont(QtGui.QFont("Sanserif", 14))
        button.setIcon(QtGui.QIcon("python.png"))
        button.setIconSize(QtCore.QSize(40, 40))
        self.buttongroup.addButton(button, 1)
        hqbox.addWidget(button)

        button2 = QPushButton("Java")
        button2.setFont(QtGui.QFont("Sanserif", 14))
        button2.setIcon(QtGui.QIcon("java.png"))
        button2.setIconSize(QtCore.QSize(40, 40))
        self.buttongroup.addButton(button2, 2)
        hqbox.addWidget(button2)

        button3 = QPushButton("PHP")
        button3.setFont(QtGui.QFont("Sanserif", 14))
        button3.setIcon(QtGui.QIcon("php.png"))
        button3.setIconSize(QtCore.QSize(40, 40))
        self.buttongroup.addButton(button3, 3)
        hqbox.addWidget(button3)

        self.setLayout(hqbox)
        self.show()

    def on_button_clicked(self, id):
        # 原始範例
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + " Was clicked.")
Beispiel #10
0
class MainWidow(QWidget):
    def __init__(self):
        super().__init__()

        self.Window_Properties()
        self.Window_Properties_Apply()
        self.Interface()

    def Window_Properties(self):
        self.title = "PyQt5 Button Group"
        self.top = 200
        self.left = 500
        self.width = 500
        self.height = 500
        self.iconName = "icon.png"


    def Window_Properties_Apply(self):
        self.setWindowTitle(self.title)
        self.setWindowIcon(QtGui.QIcon(self.iconName))
        self.setGeometry(self.top , self.left ,self.width ,self.height)



    def Interface(self):
        self.label = QLabel()
        button_twelfth = QPushButton("Twelfth")
        button_twelfth.setFont(QtGui.QFont("Sanserif" ,15))
        button_twelfth.setIcon(QtGui.QIcon("icon.png"))
        button_twelfth.setIconSize(QtCore.QSize(40 ,40))

        button_thirteenth = QPushButton("Thirteenth")
        button_fourteenth = QPushButton("Fourteeth")

        self.buttonGroup = QButtonGroup()
        self.buttonGroup.addButton(button_twelfth ,1)
        self.buttonGroup.addButton(button_thirteenth ,2)
        self.buttonGroup.addButton(button_fourteenth , 3)

        h_box = QHBoxLayout()
        h_box.addWidget(self.label)
        h_box.addWidget(button_twelfth)
        h_box.addWidget(button_thirteenth)
        h_box.addWidget(button_fourteenth)


        self.buttonGroup.buttonClicked[int].connect(self.On_Button_Clicked)
        self.setLayout(h_box)

    def On_Button_Clicked(self ,id):
        for button in self.buttonGroup.buttons():
            if button is self.buttonGroup.button(id):
                self.label.setText(button.text() + " Was Clicked")
Beispiel #11
0
class ButtonBar(QFrame):
    buttonClicked = pyqtSignal(
        str, int
    )  # Indicates the iteration number and iteration name of the button that was clicked

    def __init__(self, items: t_.Sequence[str], parent=None):
        super().__init__(parent=parent)
        # self.setFrameStyle(QFrame.Panel)
        self._bGroup = QButtonGroup(self)
        l = QHBoxLayout(self)
        for i, itemName in enumerate(items):
            b = QPushButton(itemName, parent=self)
            b.setCheckable(True)  # Toggleable
            self._bGroup.addButton(b, id=i)
            l.addWidget(b)
        self._selectedButtonId = self._bGroup.id(self._bGroup.buttons()[0])
        self._bGroup.buttons()[0].click(
        )  # Make sure at least one button is selected.
        self._bGroup.buttonClicked.connect(self._buttonSelected)
        l.setSpacing(1)  # Move buttons close together
        l.setContentsMargins(0, 0, 0, 0)
        w = QFrame(self)
        w.setFrameStyle(QFrame.Box)
        w.setLayout(l)
        scrollArea = QScrollArea(parent=self)
        scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        scrollArea.setStyleSheet("""QScrollBar:horizontal {
             height:10px;     
         }""")
        scrollArea.setWidget(w)
        scrollArea.setFixedHeight(10 + w.height())
        ll = QHBoxLayout()
        ll.setContentsMargins(0, 0, 0, 0)
        ll.addWidget(scrollArea)
        self.setLayout(ll)

    def _buttonSelected(self, btn):
        self._selectedButtonId = self._bGroup.id(btn)
        self.buttonClicked.emit(btn.text(), self._bGroup.id(btn))

    def getSelectedButtonId(self):
        return self._selectedButtonId

    def selectNextButton(self):
        id = self._selectedButtonId + 1
        if id >= len(self._bGroup.buttons()):
            id = 0
        self.setButtonSelected(id)

    def setButtonSelected(self, ID: int):
        btn = self._bGroup.button(ID)
        btn.click()
Beispiel #12
0
class Window(QDialog):
    def __init__(self):
        super().__init__()

        self.title = "Line Edit"
        self.left = 300
        self.top = 100
        self.width = 500
        self.height = 500
        self.IconName = "Icon/python.png"

        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon(self.IconName))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        hbox = QHBoxLayout()

        self.buttonGroup = QButtonGroup()

        buttonOne = QPushButton("Python")
        buttonTwo = QPushButton("Java")

        buttonOne.setIcon(QtGui.QIcon(self.IconName))
        buttonOne.setIconSize(QtCore.QSize(40, 40))

        buttonTwo.setIcon(QtGui.QIcon(self.IconName))
        buttonTwo.setIconSize(QtCore.QSize(40, 40))

        self.buttonGroup.addButton(buttonOne)
        self.buttonGroup.addButton(buttonTwo)
        self.buttonGroup.buttonClicked[int].connect(self.OnButtonClick)

        self.label = QLabel(self)

        hbox.addWidget(buttonOne)
        hbox.addWidget(buttonTwo)
        hbox.addWidget(self.label)

        self.setLayout(hbox)

        self.show()

    def OnButtonClick(self, id):
        for button in self.buttonGroup.buttons():
            if button is self.buttonGroup.button(id):
                self.label.setText(button.text() + " is clicked!")
Beispiel #13
0
class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.title = "PyQt5 QButton Group @ stu_dados"
        self.top = 500
        self.left = 500
        self.width = 500
        self.height = 500
        self.iconName = "_imagens/stuart.ico"

        self.setWindowIcon(QtGui.QIcon(self.iconName))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        hbox = QHBoxLayout()

        self.label = QLabel(self)
        self.label.setFont(QtGui.QFont("Sanserif", 15))
        hbox.addWidget(self.label)

        self.buttongroup = QButtonGroup()
        self.buttongroup.buttonClicked[int].connect(self.on_button_clicked)

        button = QPushButton("Python")
        self.buttongroup.addButton(button, 1)
        button.setFont(QtGui.QFont("Sanserif", 13))
        hbox.addWidget(button)

        button = QPushButton("Java")
        self.buttongroup.addButton(button, 2)
        button.setFont(QtGui.QFont("Sanserif", 13))
        hbox.addWidget(button)

        button = QPushButton("C++")
        self.buttongroup.addButton(button, 3)
        button.setFont(QtGui.QFont("Sanserif", 13))
        hbox.addWidget(button)

        self.setLayout(hbox)

        self.show()

    def on_button_clicked(self, id):
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + " foi clicado.")
Beispiel #14
0
class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.title = "QLine Edit"
        self.top = 100
        self.left = 100
        self.width = 400
        self.height = 120
        self.iconName = "logo.png"

        self.setWindowTitle(self.title)
        self.setWindowIcon(QtGui.QIcon(self.iconName))
        self.setGeometry(self.left, self.top, self.width, self.height)

        hbox = QHBoxLayout()

        self.label = QLabel("Hello")
        hbox.addWidget(self.label)
        self.label.setFont(QtGui.QFont("Algerian", 14))

        self.buttongroup = QButtonGroup()
        self.buttongroup.buttonClicked[int].connect(self.onButtonClicked)

        btn1 = QPushButton("Python")
        btn1.setIcon(QtGui.QIcon("python.png"))
        self.buttongroup.addButton(btn1, 1)
        hbox.addWidget(btn1)

        btn2 = QPushButton("Java")
        btn2.setIcon(QtGui.QIcon("java.png"))
        self.buttongroup.addButton(btn2, 2)
        hbox.addWidget(btn2)

        btn3 = QPushButton("C++")
        btn3.setIcon(QtGui.QIcon("Cpp.png"))
        self.buttongroup.addButton(btn3, 3)
        hbox.addWidget(btn3)
        self.setLayout(hbox)

        self.show()

    def onButtonClicked(self, id):
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + " Clicked!")
Beispiel #15
0
class window(QWidget):
    def __init__(self):
        super().__init__()
        self.title = "Pyqt5 Qbutton group"
        self.top = 500
        self.left = 500
        self.width = 100
        self.height = 200
        self.iconName = "transistor.jpg"

        self.setWindowIcon(QtGui.QIcon(self.iconName))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        hbox = QVBoxLayout()

        self.label = QLabel("Hello")
        self.label.setFont(QtGui.QFont("Sanserif", 10))
        hbox.addWidget(self.label)
        self.buttongroup = QButtonGroup()
        self.buttongroup.buttonClicked[int].connect(self.onButton_clicked)

        button = QPushButton("Python")
        self.buttongroup.addButton(button, 1)
        button.setMinimumHeight(70)
        hbox.addWidget(button)

        button1 = QPushButton("Java")
        self.buttongroup.addButton(button1, 2)
        button1.setMinimumHeight(70)
        button1.setIcon(QtGui.QIcon(self.iconName))
        button1.setIconSize(QtCore.QSize(60, 60))
        button1.setFont(QtGui.QFont("Sanserif", 15))
        hbox.addWidget(button1)

        button2 = QPushButton("JOSE")
        self.buttongroup.addButton(button2, 3)
        button2.setMinimumHeight(70)
        hbox.addWidget(button2)

        self.setLayout(hbox)
        self.show()

    def onButton_clicked(self, id):
        for button in self.buttongroup.buttons():
            if button is self.buttongroup.button(id):
                self.label.setText(button.text() + " was Clicked")
Beispiel #16
0
class MyWindow(QWidget):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.icon = QtGui.QIcon("home.ico")
        self.rect = QtCore.QRect(100,200,800,600)
        self.title = "PyQt5 BuggonGroup"

        self.setWindowIcon(self.icon)
        self.setWindowTitle(self.title)
        self.setGeometry(self.rect)
        self.label = QLabel(self)
        self.label.setText('label')
        self.button_group = QButtonGroup()
        self.InitWindow()
        self.show()

    def InitWindow(self):
        '''
        QButtonGroup的signal再使用的时候要注意如何使用[int]不要忘记了,否则会出错
        :return:
        '''
        self.button_group.buttonClicked[int].connect(self.OnButtonGroupPressed)
        vbox = QVBoxLayout()
        for i in range(1,10):
            button = QPushButton('Button %d'%i)
            button.setIcon(self.icon)
            button.setIconSize(QtCore.QSize(40,40))
            button.setFont(QtGui.QFont('lisu',20))
            self.button_group.addButton(button,i)
            vbox.addWidget(button)



        self.label.setFont(QtGui.QFont('lisu',20))
        vbox.addWidget(self.label)
        self.setLayout(vbox)

    def OnButtonGroupPressed(self,id):
        self.label.setText(self.button_group.button(id).text())
Beispiel #17
0
class EnumBase(Option):
    values = ()

    def get_value(self):
        if self.__as_radio_buttons:
            return self.values[self.__button_group.checkedId()]
        button_text = self.widget.text()
        if isinstance(self, SymbolicEnumOption):
            return self.values[self.labels.index(button_text)]
        return button_text

    def set_value(self, value):
        if self.__as_radio_buttons:
            self.__button_group.button(
                self.values.index(value)).setChecked(True)
        elif isinstance(self, SymbolicEnumOption):
            self.widget.setText(self.labels[self.values.index(value)])
        else:
            self.widget.setText(value)

    value = property(get_value, set_value)

    def set_multiple(self):
        if not self.__as_radio_buttons:
            self.widget.setText(self.multiple_value)

    def remake_menu(self):
        from PyQt5.QtWidgets import QAction, QRadioButton
        from PyQt5.QtCore import Qt
        if isinstance(self, SymbolicEnumOption):
            labels = self.labels
        else:
            labels = self.values
        if self.__as_radio_buttons:
            for b in self.__button_group.buttons():
                self.__button_group.removeButton(b)
                b.hide()
                b.destroy()
            layout = self.widget.layout()
            for i, l in enumerate(labels):
                b = QRadioButton(l)
                layout.addWidget(b, alignment=Qt.AlignLeft)
                self.__button_group.addButton(b, id=i)
        else:
            menu = self.widget.menu()
            menu.clear()
            for label, value in zip(labels, self.values):
                menu_label = label.replace('&', '&&')
                action = QAction(menu_label, self.widget)
                action.triggered.connect(
                    lambda arg, s=self, val=value: s._menu_cb(val))
                menu.addAction(action)
            if self.values and self.value not in self.values and self.value != self.multiple_value:
                self.value = labels[0]
                self.make_callback()

    remake_buttons = remake_menu

    def _make_widget(self,
                     *,
                     as_radio_buttons=False,
                     display_value=None,
                     **kw):
        from PyQt5.QtWidgets import QPushButton, QMenu, QWidget, QButtonGroup, QVBoxLayout
        self.__as_radio_buttons = as_radio_buttons
        if as_radio_buttons:
            self.widget = QWidget()
            layout = QVBoxLayout()
            self.widget.setLayout(layout)
            self.__button_group = QButtonGroup()
            self.remake_buttons()
            self.__button_group.button(self.values.index(
                self.default)).setChecked(True)
            self.__button_group.buttonClicked[int].connect(
                lambda arg: self.make_callback())
        else:
            if display_value is not None:
                button_label = display_value
            elif isinstance(self, SymbolicEnumOption):
                button_label = self.labels[self.values.index(self.default)]
            else:
                button_label = self.default
            self.widget = QPushButton(button_label, **kw)
            self.widget.setAutoDefault(False)
            menu = QMenu(self.widget)
            self.widget.setMenu(menu)
            self.remake_menu()
        return self.widget

    def _menu_cb(self, value):
        self.value = value
        self.make_callback()
Beispiel #18
0
class TimersDialog(QDialog):
    sendCommand = pyqtSignal(str, str)

    def __init__(self, device, *args, **kwargs):
        super(TimersDialog, self).__init__(*args, **kwargs)
        self.device = device
        self.timers = {}
        self.setWindowTitle("Timers [{}]".format(
            self.device.p['FriendlyName1']))

        vl = VLayout()

        self.gbTimers = GroupBoxV("Enabled", spacing=5)
        self.gbTimers.setCheckable(True)
        self.gbTimers.toggled.connect(self.toggleTimers)

        self.cbTimer = QComboBox()
        self.cbTimer.addItems(["Timer{}".format(nr + 1) for nr in range(16)])
        self.cbTimer.currentTextChanged.connect(self.loadTimer)

        hl_tmr_arm_rpt = HLayout(0)
        self.cbTimerArm = QCheckBox("Arm")
        self.cbTimerArm.clicked.connect(lambda x: self.describeTimer())
        self.cbTimerRpt = QCheckBox("Repeat")
        self.cbTimerRpt.clicked.connect(lambda x: self.describeTimer())
        hl_tmr_arm_rpt.addWidgets([self.cbTimerArm, self.cbTimerRpt])

        hl_tmr_out_act = HLayout(0)
        self.cbxTimerOut = QComboBox()
        self.cbxTimerOut.addItems(self.device.power().keys())
        self.cbxTimerOut.currentIndexChanged.connect(
            lambda x: self.describeTimer())
        self.cbxTimerAction = QComboBox()
        self.cbxTimerAction.addItems(["Off", "On", "Toggle", "Rule"])
        self.cbxTimerAction.currentIndexChanged.connect(
            lambda x: self.describeTimer())
        hl_tmr_out_act.addWidgets([self.cbxTimerOut, self.cbxTimerAction])

        self.TimerMode = QButtonGroup()
        rbTime = QRadioButton("Time")
        rbSunrise = QRadioButton("Sunrise ({})".format(
            self.device.p['Sunrise']))
        rbSunset = QRadioButton("Sunset ({})".format(self.device.p['Sunset']))
        self.TimerMode.addButton(rbTime, 0)
        self.TimerMode.addButton(rbSunrise, 1)
        self.TimerMode.addButton(rbSunset, 2)
        self.TimerMode.buttonClicked.connect(lambda x: self.describeTimer())
        gbTimerMode = GroupBoxH("Mode")
        gbTimerMode.addWidgets(self.TimerMode.buttons())

        hl_tmr_time = HLayout(0)
        self.cbxTimerPM = QComboBox()
        self.cbxTimerPM.addItems(["+", "-"])
        self.cbxTimerPM.currentIndexChanged.connect(
            lambda x: self.describeTimer())

        self.TimerMode.buttonClicked[int].connect(
            lambda x: self.cbxTimerPM.setEnabled(x != 0))
        self.teTimerTime = QTimeEdit()
        self.teTimerTime.setButtonSymbols(QTimeEdit.NoButtons)
        self.teTimerTime.setAlignment(Qt.AlignCenter)
        self.teTimerTime.timeChanged.connect(lambda x: self.describeTimer())

        lbWnd = QLabel("Window:")
        lbWnd.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
        self.cbxTimerWnd = QComboBox()
        self.cbxTimerWnd.addItems([str(x).zfill(2) for x in range(0, 16)])
        self.cbxTimerWnd.currentIndexChanged.connect(
            lambda x: self.describeTimer())

        hl_tmr_days = HLayout(0)
        self.TimerWeekday = QButtonGroup()
        self.TimerWeekday.setExclusive(False)
        for i, wd in enumerate(
            ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]):
            cb = QCheckBox(wd)
            cb.clicked.connect(lambda x: self.describeTimer())
            hl_tmr_days.addWidget(cb)
            self.TimerWeekday.addButton(cb, i)

        gbTimerDesc = GroupBoxV("Timer description", 5)
        gbTimerDesc.setMinimumHeight(200)
        self.lbTimerDesc = QLabel()
        self.lbTimerDesc.setAlignment(Qt.AlignCenter)
        self.lbTimerDesc.setWordWrap(True)
        gbTimerDesc.layout().addWidget(self.lbTimerDesc)

        hl_tmr_time.addWidgets(
            [self.cbxTimerPM, self.teTimerTime, lbWnd, self.cbxTimerWnd])

        self.gbTimers.layout().addWidget(self.cbTimer)
        self.gbTimers.layout().addLayout(hl_tmr_arm_rpt)
        self.gbTimers.layout().addLayout(hl_tmr_out_act)
        self.gbTimers.layout().addWidget(gbTimerMode)
        self.gbTimers.layout().addLayout(hl_tmr_time)
        self.gbTimers.layout().addLayout(hl_tmr_days)

        btns = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close)
        reload = btns.addButton("Reload", QDialogButtonBox.ResetRole)

        btns.accepted.connect(self.saveTimer)
        btns.rejected.connect(self.reject)
        reload.clicked.connect(
            lambda: self.loadTimer(self.cbTimer.currentText()))

        vl.addWidgets([self.gbTimers, gbTimerDesc, btns])
        self.setLayout(vl)

    def toggleTimers(self, state):
        self.sendCommand.emit(self.device.cmnd_topic('timers'),
                              "ON" if state else "OFF")

    def loadTimer(self, timer=""):
        if not timer:
            timer = self.cbTimer.currentText()
        payload = self.timers[timer]

        if payload:
            self.blockSignals(True)
            self.cbTimerArm.setChecked(payload['Arm'])
            self.cbTimerRpt.setChecked(payload['Repeat'])
            self.cbxTimerAction.setCurrentIndex(payload['Action'])

            output = payload.get('Output')
            if output:
                self.cbxTimerOut.setEnabled(True)
                self.cbxTimerOut.setCurrentIndex(output - 1)
            else:
                self.cbxTimerOut.setEnabled(False)

            mode = payload.get('Mode', 0)
            self.TimerMode.button(mode).setChecked(True)

            h, m = map(int, payload["Time"].split(":"))
            if h < 0:
                self.cbxTimerPM.setCurrentText("-")
                h *= -1
            self.teTimerTime.setTime(QTime(h, m))
            self.cbxTimerWnd.setCurrentText(str(payload['Window']).zfill(2))
            for wd, v in enumerate(payload['Days']):
                self.TimerWeekday.button(wd).setChecked(int(v))

            self.blockSignals(False)
            self.describeTimer()

    def describeTimer(self):
        if self.cbTimerArm.isChecked():
            desc = {
                'days': '',
                'repeat': '',
                'timer': self.cbTimer.currentText().upper()
            }
            repeat = self.cbTimerRpt.isChecked()
            out = self.cbxTimerOut.currentText()
            act = self.cbxTimerAction.currentText()
            mode = self.TimerMode.checkedId()
            pm = self.cbxTimerPM.currentText()
            time = self.teTimerTime.time()
            wnd = int(self.cbxTimerWnd.currentText()) * 60

            if mode == 0:
                if wnd == 0:
                    desc['time'] = "at {}".format(time.toString("hh:mm"))
                else:
                    desc['time'] = "somewhere between {} and {}".format(
                        time.addSecs(wnd * -1).toString("hh:mm"),
                        time.addSecs(wnd).toString("hh:mm"))
            else:
                prefix = "before" if pm == "-" else "after"
                mode_desc = "sunrise" if mode == 1 else "sunset"
                window = "somewhere in a {} minute window centered around ".format(
                    wnd // 30)
                desc['time'] = "{}h{}m {} {}".format(time.hour(),
                                                     time.minute(), prefix,
                                                     mode_desc)

                if wnd > 0:
                    desc['time'] = window + desc['time']

            if repeat:
                day_names = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
                days = [cb.isChecked() for cb in self.TimerWeekday.buttons()]
                if days.count(True) == 7:
                    desc['days'] = "everyday"
                else:
                    days_list = [day_names[d] for d in range(7) if days[d]]
                    desc['days'] = "on every {}".format(", ".join(days_list))
            else:
                desc['repeat'] = "only ONCE"

            if act == "Rule":
                desc['action'] = "trigger clock#Timer={}".format(
                    self.cbTimer.currentIndex() + 1)
                text = "{timer} will {action} {time} {days} {repeat}".format(
                    **desc)

            elif self.cbxTimerOut.count() > 0:

                if act == "Toggle":
                    desc['action'] = "TOGGLE {}".format(out.upper())
                else:
                    desc['action'] = "set {} to {}".format(
                        out.upper(), act.upper())

                text = "{timer} will {action} {time} {days} {repeat}".format(
                    **desc)
            else:
                text = "{timer} will do nothing because there are no relays configured.".format(
                    **desc)

            self.lbTimerDesc.setText(text)

        else:
            self.lbTimerDesc.setText(
                "{} is not armed, it will do nothing.".format(
                    self.cbTimer.currentText().upper()))

    def saveTimer(self):
        payload = {
            "Arm":
            int(self.cbTimerArm.isChecked()),
            "Mode":
            self.TimerMode.checkedId(),
            "Time":
            self.teTimerTime.time().toString("hh:mm"),
            "Window":
            self.cbxTimerWnd.currentIndex(),
            "Days":
            "".join([
                str(int(cb.isChecked())) for cb in self.TimerWeekday.buttons()
            ]),
            "Repeat":
            int(self.cbTimerRpt.isChecked()),
            "Output":
            self.cbxTimerOut.currentIndex() + 1,
            "Action":
            self.cbxTimerAction.currentIndex()
        }
        self.sendCommand.emit(
            self.device.cmnd_topic(self.cbTimer.currentText()), dumps(payload))
        QMessageBox.information(
            self, "Timer saved",
            "{} data sent to device.".format(self.cbTimer.currentText()))

    @pyqtSlot(str, str)
    def parseMessage(self, topic, msg):
        if self.device.matches(topic):
            if self.device.reply == "RESULT" or self.device.reply == "TIMERS":
                try:
                    payload = loads(msg)
                    first = list(payload)[0]

                except JSONDecodeError as e:
                    error = "Timer loading error", "Can't load the timer from device.\n{}".format(
                        e)
                    logging.critical(error)
                    QMessageBox.critical(self, error)

                else:
                    if first == 'Timers':
                        self.gbTimers.setChecked(payload[first] == "ON")

                    elif first.startswith('Timers'):
                        self.timers.update(payload[first])

                    if first == 'Timers4':
                        self.loadTimer(self.cbTimer.currentText())
Beispiel #19
0
class SettingsDialog(QDialog, Ui_Dialog):
    def __init__(self, parent):
        super().__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setupUi(self)

        self.lineEdit_loginUsername.setText(
            app.settings.get("account", "username"))
        self.lineEdit_loginPassword.setText(
            app.settings.get("account", "password"))
        self.checkBox_autoLogin.setChecked(
            app.settings.getbool("account", "autologin"))
        self.checkBox_autoStartFrontend.setChecked(app.autoStart)

        # Xwared Management
        managedBySystemd = app.xwaredpy.managedBySystemd
        managedByUpstart = app.xwaredpy.managedByUpstart
        managedByAutostart = app.xwaredpy.managedByAutostart

        self.radio_managedBySystemd.setChecked(managedBySystemd)
        self.radio_managedByUpstart.setChecked(managedByUpstart)
        self.radio_managedByAutostart.setChecked(managedByAutostart)
        self.radio_managedByNothing.setChecked(not (
            managedBySystemd or managedByUpstart or managedByAutostart))

        initType = getInitType()
        self.radio_managedBySystemd.setEnabled(initType == InitType.SYSTEMD)
        self.radio_managedByUpstart.setEnabled(initType == InitType.UPSTART)

        # frontend
        self.checkBox_enableDevelopersTools.setChecked(
            app.settings.getbool("frontend", "enabledeveloperstools"))
        self.checkBox_allowFlash.setChecked(
            app.settings.getbool("frontend", "allowflash"))
        self.checkBox_minimizeToSystray.setChecked(
            app.settings.getbool("frontend", "minimizetosystray"))
        self.checkBox_closeToMinimize.setChecked(
            app.settings.getbool("frontend", "closetominimize"))
        self.checkBox_popNotifications.setChecked(
            app.settings.getbool("frontend", "popnotifications"))
        self.checkBox_notifyBySound.setChecked(
            app.settings.getbool("frontend", "notifybysound"))
        self.checkBox_showMonitorWindow.setChecked(
            app.settings.getbool("frontend", "showmonitorwindow"))
        self.spinBox_monitorFullSpeed.setValue(
            app.settings.getint("frontend", "monitorfullspeed"))

        # clipboard related
        self.checkBox_watchClipboard.stateChanged.connect(
            self.slotWatchClipboardToggled)
        self.checkBox_watchClipboard.setChecked(
            app.settings.getbool("frontend", "watchclipboard"))
        self.slotWatchClipboardToggled(
            self.checkBox_watchClipboard.checkState())
        self.plaintext_watchPattern.setPlainText(
            app.settings.get("frontend", "watchpattern"))

        self.btngrp_etmStartWhen = QButtonGroup()
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3)

        startEtmWhen = app.xwaredpy.startEtmWhen
        if startEtmWhen:
            self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True)
        else:
            self.group_etmStartWhen.setEnabled(False)

        self.btn_addMount.clicked.connect(self.slotAddMount)
        self.btn_removeMount.clicked.connect(self.slotRemoveMount)

        # Mounts
        self.setupMounts()

        # backend setting is a different thing!
        self.setupETM()

    @pyqtSlot(int)
    def slotWatchClipboardToggled(self, state):
        self.plaintext_watchPattern.setEnabled(state)

    @pyqtSlot()
    def setupMounts(self):
        self.table_mounts.setRowCount(0)
        self.table_mounts.clearContents()

        mountsMapping = app.mountsFaker.getMountsMapping()
        for i, mount in enumerate(app.mountsFaker.mounts):
            self.table_mounts.insertRow(i)
            # drive1: the drive letter it should map to, by alphabetical order
            drive1 = app.mountsFaker.driveIndexToLetter(i)
            self.table_mounts.setItem(
                i, 0, QTableWidgetItem(drive1 + "\\TDDOWNLOAD"))

            # mounts = ['/path/to/1', 'path/to/2', ...]
            self.table_mounts.setItem(i, 1, QTableWidgetItem(mount))

            # drive2: the drive letter it actually is assigned to
            drive2 = mountsMapping.get(mount, "无")

            errors = []

            # check: mapping
            if drive1 != drive2:
                errors.append("错误:盘符映射在'{actual}',而不是'{should}'。\n"
                              "如果这是个新挂载的文件夹,请尝试稍等,或重启后端,可能会修复此问题。".format(
                                  actual=drive2, should=drive1))

            brush = QBrush()
            if errors:
                brush.setColor(Qt.red)
                errString = "\n".join(errors)
            else:
                brush.setColor(Qt.darkGreen)
                errString = "正常"
            errWidget = QTableWidgetItem(errString)
            errWidget.setForeground(brush)

            self.table_mounts.setItem(i, 2, errWidget)
            del brush, errWidget

        self.table_mounts.resizeColumnsToContents()

    @pyqtSlot()
    def slotAddMount(self):
        fileDialog = QFileDialog(self, Qt.Dialog)
        fileDialog.setFileMode(QFileDialog.Directory)
        fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
        fileDialog.setViewMode(QFileDialog.List)
        fileDialog.setDirectory(os.environ["HOME"])
        if fileDialog.exec():
            selected = fileDialog.selectedFiles()[0]
            if selected in self.newMounts:
                return
            row = self.table_mounts.rowCount()
            self.table_mounts.insertRow(row)
            self.table_mounts.setItem(
                row, 0,
                QTableWidgetItem(
                    app.mountsFaker.driveIndexToLetter(row) + "\\TDDOWNLOAD"))
            self.table_mounts.setItem(row, 1, QTableWidgetItem(selected))
            self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加"))

    @pyqtSlot()
    def slotRemoveMount(self):
        row = self.table_mounts.currentRow()
        self.table_mounts.removeRow(row)

    @pyqtSlot()
    def accept(self):
        app.settings.set("account", "username",
                         self.lineEdit_loginUsername.text())
        app.settings.set("account", "password",
                         self.lineEdit_loginPassword.text())
        app.settings.setbool("account", "autologin",
                             self.checkBox_autoLogin.isChecked())

        app.autoStart = self.checkBox_autoStartFrontend.isChecked()

        app.xwaredpy.managedBySystemd = self.radio_managedBySystemd.isChecked()
        app.xwaredpy.managedByUpstart = self.radio_managedByUpstart.isChecked()
        app.xwaredpy.managedByAutostart = self.radio_managedByAutostart.isChecked(
        )

        app.settings.setbool("frontend", "enabledeveloperstools",
                             self.checkBox_enableDevelopersTools.isChecked())
        app.settings.setbool("frontend", "allowflash",
                             self.checkBox_allowFlash.isChecked())
        app.settings.setbool("frontend", "minimizetosystray",
                             self.checkBox_minimizeToSystray.isChecked())

        # A possible Qt bug
        # https://bugreports.qt-project.org/browse/QTBUG-37695
        app.settings.setbool("frontend", "closetominimize",
                             self.checkBox_closeToMinimize.isChecked())
        app.settings.setbool("frontend", "popnotifications",
                             self.checkBox_popNotifications.isChecked())
        app.settings.setbool("frontend", "notifybysound",
                             self.checkBox_notifyBySound.isChecked())

        app.settings.setbool("frontend", "showmonitorwindow",
                             self.checkBox_showMonitorWindow.isChecked())
        app.settings.setint("frontend", "monitorfullspeed",
                            self.spinBox_monitorFullSpeed.value())
        app.settings.setbool("frontend", "watchclipboard",
                             self.checkBox_watchClipboard.isChecked())
        app.settings.set("frontend", "watchpattern",
                         self.plaintext_watchPattern.toPlainText())

        if self.group_etmStartWhen.isEnabled():
            startEtmWhen = self.btngrp_etmStartWhen.id(
                self.btngrp_etmStartWhen.checkedButton())
            try:
                app.xwaredpy.startEtmWhen = startEtmWhen
            except InvalidSocket:
                QMessageBox.warning(
                    None, "Xware Desktop",
                    "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()),
                    QMessageBox.Ok, QMessageBox.Ok)

        app.settings.save()

        app.mountsFaker.mounts = self.newMounts
        app.settings.applySettings.emit()
        super().accept()

    @property
    def newMounts(self):
        return list(
            map(lambda row: self.table_mounts.item(row, 1).text(),
                range(self.table_mounts.rowCount())))

    @pyqtSlot()
    def setupETM(self):
        # fill values
        lcPort = app.xwaredpy.lcPort
        self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用")

        etmSettings = app.etmpy.getSettings()
        if etmSettings:
            self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit)
            self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit)
            self.spinBox_maxRunningTasksNum.setValue(
                etmSettings.maxRunningTasksNum)

            # connect signals
            self.accepted.connect(self.saveETM)
        else:
            self.spinBox_dSpeedLimit.setEnabled(False)
            self.spinBox_uSpeedLimit.setEnabled(False)
            self.spinBox_maxRunningTasksNum.setEnabled(False)

    @pyqtSlot()
    def saveETM(self):
        newsettings = EtmSetting(
            dLimit=self.spinBox_dSpeedLimit.value(),
            uLimit=self.spinBox_uSpeedLimit.value(),
            maxRunningTasksNum=self.spinBox_maxRunningTasksNum.value())

        app.etmpy.saveSettings(newsettings)
class parameter():

    def __init__(self, const, vary):
        self.const = const
        self.vary = vary
        self.constPara = []
        self.varyPara = []
        self.pp = []
        for i in range(vary):
            self.pp.append(property.property())

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1200, 800)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(40, 30, 171, 16))
        self.label.setText("Parameter Setting")
        self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(40, 80, 1000, 700))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")

        # list for vary paramter label
        self.name = []
        self.combo = []
        self.range = []
        self.rfield = []
        self.check = []
        self.add = []
        self.other = []
        self.othername = []

        # list for const paramter label
        self.cname = []
        self.ccombo = []
        self.cvalue = []
        self.crfield = []
        self.cadd = []
        self.cother = []
        self.cothername = []

        self.btn_grp = QButtonGroup()
        self.btn_grp.buttonClicked[int].connect(self.addSession)

        for i in range(self.vary):
            self.name.append(QtWidgets.QLabel(self.gridLayoutWidget))
            self.name[i].setText("Varying parameter" + str(i + 1))
            self.gridLayout.addWidget(self.name[i], i, 0, 1, 1)
            self.name[i].adjustSize()

            self.combo.append(QtWidgets.QComboBox(self.gridLayoutWidget))
            self.combo[i].setObjectName("comboBox")
            self.combo[i].addItem("Keithley 2440 cur (A)")
            self.combo[i].addItem("Keithley 2440 com (V)")
            self.combo[i].addItem("Keithley 6221 cur (A)")
            self.combo[i].addItem("Keithley 6221 com (V)")
            self.combo[i].addItem("Keithley 6221 amp (A)")
            self.combo[i].addItem("Keithley 6221 fre (Hz)")
            self.combo[i].addItem("Keithley 6221 duration")
            self.combo[i].addItem("Angle")
            self.combo[i].addItem("Other")
            self.gridLayout.addWidget(self.combo[i], i, 1, 1, 1)
            self.combo[i].adjustSize()
            self.pp[i].savename = "Keithley 2440 cur (A)"
            self.combo[i].currentTextChanged.connect(partial(self.changetoother, i, True))

            self.other.append(QtWidgets.QLabel(self.gridLayoutWidget))
            self.other[i].setText("Other: ")
            self.gridLayout.addWidget(self.other[i], i, 2, 1, 1)
            self.other[i].adjustSize()

            self.othername.append(QtWidgets.QLineEdit(self.gridLayoutWidget))
            self.gridLayout.addWidget(self.othername[i], i, 3, 1, 1)
            self.othername[i].textChanged.connect(partial(self.savename, i))

            self.range.append(QtWidgets.QLabel(self.gridLayoutWidget))
            self.range[i].setText("Range")
            self.gridLayout.addWidget(self.range[i], i, 4, 1, 1)
            self.range[i].adjustSize()

            self.rfield.append(QtWidgets.QLineEdit(self.gridLayoutWidget))
            self.rfield[i].setText(self.pp[i].saverange[0])
            self.gridLayout.addWidget(self.rfield[i], i, 5, 1, 1)
            # save range property whenever text changed
            self.rfield[i].textChanged.connect(partial(self.saverfield, i))

            self.check.append(QtWidgets.QCheckBox(self.gridLayoutWidget))
            self.check[i].setText("sweep")
            self.check[i].setChecked(self.pp[i].savesweep[0])
            self.gridLayout.addWidget(self.check[i], i, 6, 1, 1)

            self.check[i].clicked.connect(partial(self.savescheck, i))

            self.add.append(QtWidgets.QPushButton(self.gridLayoutWidget))
            self.add[i].setText("Add")
            self.add[i].setObjectName(str(i))
            self.gridLayout.addWidget(self.add[i], i, 7, 1, 1)
            self.btn_grp.addButton(self.add[i], i)

        for i in range(self.const):
            self.cname.append(QtWidgets.QLabel(self.gridLayoutWidget))
            self.cname[i].setText("Constant parameter" + str(i + 1))
            self.gridLayout.addWidget(self.cname[i], i + self.vary, 0, 1, 1)
            self.cname[i].adjustSize()

            self.ccombo.append(QtWidgets.QComboBox(self.gridLayoutWidget))
            self.ccombo[i].setObjectName("comboBox")
            self.ccombo[i].addItem("Keithley 2440 cur (A)")
            self.ccombo[i].addItem("Keithley 2440 com (V)")
            self.ccombo[i].addItem("Keithley 6221 cur (A)")
            self.ccombo[i].addItem("Keithley 6221 com (V)")
            self.ccombo[i].addItem("Keithley 6221 amp (A)")
            self.ccombo[i].addItem("Keithley 6221 fre (Hz)")
            self.ccombo[i].addItem("Keithley 6221 duration")
            self.ccombo[i].addItem("Angle")
            self.ccombo[i].addItem("Other")
            self.gridLayout.addWidget(self.ccombo[i], i + self.vary, 1, 1, 1)
            self.ccombo[i].adjustSize()

            self.cother.append(QtWidgets.QLabel(self.gridLayoutWidget))
            self.cother[i].setText("Other:")
            self.gridLayout.addWidget(self.cother[i], i + self.vary, 2, 1, 1)
            self.cother[i].adjustSize()

            self.cothername.append(QtWidgets.QLineEdit(self.gridLayoutWidget))
            self.gridLayout.addWidget(self.cothername[i], i + self.vary, 3, 1, 1)
            self.cothername[i].textChanged.connect(partial(self.changetoother, i, False))

            self.cvalue.append(QtWidgets.QLabel(self.gridLayoutWidget))
            self.cvalue[i].setText("Constant Value")
            self.gridLayout.addWidget(self.cvalue[i], i + self.vary, 4, 1, 1)
            self.cvalue[i].adjustSize()

            self.crfield.append(QtWidgets.QLineEdit(self.gridLayoutWidget))
            self.crfield[i].setText("const")
            self.gridLayout.addWidget(self.crfield[i], i + self.vary, 5, 1, 1)

        self.genBtn = QtWidgets.QPushButton(self.gridLayoutWidget)
        self.genBtn.setText("Generate")
        self.gridLayout.addWidget(self.genBtn, i + self.vary + 1, 4, 1, 1)
        self.genBtn.clicked.connect(lambda: self.generate_handler())

        for i in range(self.vary):
            self.pp[i].bind_to(self.update)

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 422, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        QtCore.QMetaObject.connectSlotsByName(MainWindow)


    def generate_handler(self):
        # varying
        for i in range(self.vary):
            slist = self.pp[i].savesweep
            name = self.pp[i].savename
            list = self.pp[i].saverange
            check = self.checkrange(self.rfield[i].text(), i)
            if not check:
                return
            self.varyPara.append(varyPara.VaryPara(name, list, slist))

        # const
        for i in range(self.const):
            const = self.crfield[i].text()
            check = self.checknum(const, i, False)
            if not check:
                return
            checkbound = self.checkboundary(const, i, False)
            if not checkbound:
                return
            if self.ccombo[i].currentText() == "Other":
                name = self.cothername[i].text()
            else:
                name = self.ccombo[i].currentText()
            self.constPara.append(constPara.ConstPara(name, const))

        file = WriteFile.inputFile(self.varyPara, self.constPara)

    def saverfield(self, i, text):
        self.pp[i].saverange[0] = text

    def savescheck(self, i, text):
        self.pp[i].savesweep[0] = text

    def savename(self, i, text):
        if self.combo[i].currentText() != "Other":
            self.combo[i].setCurrentText("Other")
        self.pp[i].savename = text
        self.pp[i].setname(text)
        print(self.pp[i].savename)

    def addSession(self, button_id):
        for btn in self.btn_grp.buttons():
            if btn is self.btn_grp.button(button_id):
                self.openwindow(self.pp[button_id])

    def changetoother(self, i, vary):
        if vary:
            if self.othername[i].text() != "":
                self.combo[i].setCurrentText("Other")
                self.pp[i].savename = self.othername[i].text()
            self.pp[i].setname(self.combo[i].currentText())
        else:
            if self.cothername[i].text() != "":
                self.ccombo[i].setCurrentText("Other")

    def openwindow(self, status):
        self.window = QtWidgets.QMainWindow()
        self.ui = add(status)
        self.ui.setupUi(self.window)
        self.window.show()

    def update(self):
        for i in range(self.vary):
            self.rfield[i].setText(self.pp[i].saverange[0])
            self.check[i].setChecked(self.pp[i].savesweep[0])

    def checkrange(self, text, i):
        try:
            numbers = text.split(",")
            num1 = numbers[0]
            num2 = numbers[1]
            check1 = self.checknum(num1, i, True)
            check2 = self.checknum(num2, i, True)
            check3 = numbers[2].isdigit()
            num3 = int(numbers[2])
            check4 = num3 >= 0
            if not (check1 and check2 and check3 and check4):
                self.popErrorWindow("Wrong input range format at " + str(i + 1) + "th vary item.")
                return
            checkbound1 = self.checkboundary(num1, i, True)
            checkbound2 = self.checkboundary(num2, i, True)
            return check1 and check2 and check3 and checkbound1 and checkbound2
        except:
            self.popErrorWindow("Wrong input range format at " + str(i + 1) + "th vary item hh.")
            return False

    def checkboundary(self, num, index, vary):
        try:
            cur_path = os.path.dirname(__file__)
            new_path = os.path.join(cur_path, '..', 'input', 'boundary.txt')
            file1 = open(new_path, "r+")
            text = file1.readlines()
            for i in range(len(text)):
                text[i] = text[i].replace('\n', '')
                x = re.split("<=|>=|<|>", text[i])
                y = re.findall("<=|>=|<|>", text[i])
                y = y[0]
                if vary:
                    name = self.pp[index].savename
                    if name == x[0]:
                        if y == ">":
                            if not float(num) > float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th vary item should > " + str(x[1]))
                                return False
                        if y == "<":
                            if not float(num) < float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th vary item should < " + str(x[1]))
                                return False
                        if y == ">=":
                            if not float(num) >= float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th vary item should >= " + str(x[1]))
                                return False
                        if y == "<=":
                            if not float(num) <= float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th vary item should <= " + str(x[1]))
                                return False
                else:
                    if self.ccombo[index].currentText() == "Other":
                        name = self.cothername[index].text()
                    else:
                        name = self.ccombo[index].currentText()
                    if name == x[0]:
                        if y == ">":
                            if not float(num) > float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th const item should > " + str(x[1]))
                                return False
                        if y == "<":
                            if not float(num) < float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th const item should < " + str(x[1]))
                                return False
                        if y == ">=":
                            if not float(num) >= float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th const item should >= " + str(x[1]))
                                return False
                        if y == "<=":
                            if not float(num) <= float(x[1]):
                                file1.close()
                                self.popErrorWindow(
                                    "Warning: Value at " + str(index + 1) + "th const item should <= " + str(x[1]))
                                return False
            file1.close()
            return True
        except:
            self.popErrorWindow("Fail to read boundary.txt")
            return False

    def checknum(self, text, i, vary):
        y = re.fullmatch("[0-9]*[.][0-9]*|[-][0-9]*[.][0-9]*|[0-9]*|[-][0-9]*", text)
        if y is None:
            if vary:
                self.popErrorWindow("Range must be integers/float at " + str(i + 1) + "th vary item.")
            if not vary:
                self.popErrorWindow("Constant value must be integers/float at " + str(i + 1) + "th const item.")
            return False
        return True

    def popErrorWindow(self, msg):
        self.window = QtWidgets.QMainWindow()
        self.ui = ErrorPane.error(msg)
        self.ui.setupUi(self.window)
        self.window.show()
Beispiel #21
0
class SettingsDialog(QDialog, Ui_Dialog):
    def __init__(self, parent):
        super().__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setupUi(self)

        self.lineEdit_loginUsername.setText(app.settings.get("adapter-legacy", "username"))
        self.lineEdit_loginPassword.setText(app.settings.get("adapter-legacy", "password"))
        self.checkBox_autoLogin.setChecked(app.settings.getbool("legacy", "autologin"))
        self.checkBox_autoStartFrontend.setChecked(app.autoStart)
        if sys.platform == "linux":
            self.checkBox_autoStartFrontend.setEnabled(True)

        adapter = app.adapterManager[0]

        # Xwared Management
        managedBySystemd = adapter.daemonManagedBySystemd
        managedByUpstart = adapter.daemonManagedByUpstart
        managedByAutostart = adapter.daemonManagedByAutostart

        self.radio_managedBySystemd.setChecked(managedBySystemd)
        self.radio_managedByUpstart.setChecked(managedByUpstart)
        self.radio_managedByAutostart.setChecked(managedByAutostart)
        self.radio_managedByNothing.setChecked(
            not (managedBySystemd or managedByUpstart or managedByAutostart))

        initType = getInitType()
        self.radio_managedBySystemd.setEnabled(initType == InitType.SYSTEMD)
        self.radio_managedByUpstart.setEnabled(initType == InitType.UPSTART)

        if not adapter.useXwared:
            self.group_etmStartWhen.setEnabled(False)
            self.group_initManaged.setEnabled(False)

        self.btngrp_etmStartWhen = QButtonGroup()
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3)

        if adapter.useXwared:
            startEtmWhen = adapter.startEtmWhen
            self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True)

        # frontend
        self.checkBox_enableDevelopersTools.setChecked(
            app.settings.getbool("legacy", "enabledeveloperstools"))
        self.checkBox_allowFlash.setChecked(app.settings.getbool("legacy", "allowflash"))
        self.checkBox_minimizeToSystray.setChecked(
            app.settings.getbool("frontend", "minimizetosystray"))
        self.checkBox_closeToMinimize.setChecked(
            app.settings.getbool("frontend", "closetominimize"))
        self.checkBox_popNotifications.setChecked(
            app.settings.getbool("frontend", "popnotifications"))
        self.checkBox_notifyBySound.setChecked(
            app.settings.getbool("frontend", "notifybysound"))
        self.checkBox_showMonitorWindow.setChecked(
            app.settings.getbool("frontend", "showmonitorwindow"))
        self.spinBox_monitorFullSpeed.setValue(
            app.settings.getint("frontend", "monitorfullspeed"))

        # clipboard related
        self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled)
        self.checkBox_watchClipboard.setChecked(app.settings.getbool("frontend", "watchclipboard"))
        self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState())
        self.plaintext_watchPattern.setPlainText(app.settings.get("frontend", "watchpattern"))

        self.btn_addMount.clicked.connect(self.slotAddMount)
        self.btn_removeMount.clicked.connect(self.slotRemoveMount)

        # Mounts
        self.setupMounts()

        # backend setting is a different thing!
        self.setupETM()

    @pyqtSlot(int)
    def slotWatchClipboardToggled(self, state):
        self.plaintext_watchPattern.setEnabled(state)

    @pyqtSlot()
    def setupMounts(self):
        adapter = app.adapterManager[0]
        if not adapter.useXwared:
            self.tab_mount.setEnabled(False)
            return
        self.table_mounts.setRowCount(0)
        self.table_mounts.clearContents()

        mountsMapping = app.adapterManager[0].mountsFaker.getMountsMapping()
        for i, mount in enumerate(app.adapterManager[0].mountsFaker.mounts):
            self.table_mounts.insertRow(i)
            # drive1: the drive letter it should map to, by alphabetical order
            drive1 = app.adapterManager[0].mountsFaker.driveIndexToLetter(i)
            self.table_mounts.setItem(i, 0, QTableWidgetItem(drive1 + "\\TDDOWNLOAD"))

            # mounts = ['/path/to/1', 'path/to/2', ...]
            self.table_mounts.setItem(i, 1, QTableWidgetItem(mount))

            # drive2: the drive letter it actually is assigned to
            drive2 = mountsMapping.get(mount, "无")

            errors = []

            # check: mapping
            if drive1 != drive2:
                errors.append(
                    "错误:盘符映射在'{actual}',而不是'{should}'。\n"
                    "如果这是个新挂载的文件夹,请尝试稍等,或重启后端,可能会修复此问题。"
                    .format(actual = drive2, should = drive1))

            brush = QBrush()
            if errors:
                brush.setColor(Qt.red)
                errString = "\n".join(errors)
            else:
                brush.setColor(Qt.darkGreen)
                errString = "正常"
            errWidget = QTableWidgetItem(errString)
            errWidget.setForeground(brush)

            self.table_mounts.setItem(i, 2, errWidget)
            del brush, errWidget

        self.table_mounts.resizeColumnsToContents()

    @pyqtSlot()
    def slotAddMount(self):
        fileDialog = QFileDialog(self, Qt.Dialog)
        fileDialog.setFileMode(QFileDialog.Directory)
        fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
        fileDialog.setViewMode(QFileDialog.List)
        fileDialog.setDirectory(os.environ["HOME"])
        if fileDialog.exec():
            selected = fileDialog.selectedFiles()[0]
            if selected in self.newMounts:
                return
            row = self.table_mounts.rowCount()
            self.table_mounts.insertRow(row)
            self.table_mounts.setItem(
                row, 0,
                QTableWidgetItem(app.adapterManager[0].mountsFaker.driveIndexToLetter(row) +
                                 "\\TDDOWNLOAD"))
            self.table_mounts.setItem(row, 1, QTableWidgetItem(selected))
            self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加"))

    @pyqtSlot()
    def slotRemoveMount(self):
        row = self.table_mounts.currentRow()
        self.table_mounts.removeRow(row)

    @pyqtSlot()
    def accept(self):
        app.settings.set("adapter-legacy", "username", self.lineEdit_loginUsername.text())
        app.settings.set("adapter-legacy", "password", self.lineEdit_loginPassword.text())
        app.settings.setbool("legacy", "autologin", self.checkBox_autoLogin.isChecked())

        app.autoStart = self.checkBox_autoStartFrontend.isChecked()

        app.adapterManager[0].daemonManagedBySystemd = self.radio_managedBySystemd.isChecked()
        app.adapterManager[0].daemonManagedByUpstart = self.radio_managedByUpstart.isChecked()
        app.adapterManager[0].daemonManagedByAutostart = self.radio_managedByAutostart.isChecked()

        app.settings.setbool("legacy", "enabledeveloperstools",
                             self.checkBox_enableDevelopersTools.isChecked())
        app.settings.setbool("legacy", "allowflash",
                             self.checkBox_allowFlash.isChecked())
        app.settings.setbool("frontend", "minimizetosystray",
                             self.checkBox_minimizeToSystray.isChecked())

        # A possible Qt bug
        # https://bugreports.qt-project.org/browse/QTBUG-37695
        app.settings.setbool("frontend", "closetominimize",
                             self.checkBox_closeToMinimize.isChecked())
        app.settings.setbool("frontend", "popnotifications",
                             self.checkBox_popNotifications.isChecked())
        app.settings.setbool("frontend", "notifybysound",
                             self.checkBox_notifyBySound.isChecked())

        app.settings.setbool("frontend", "showmonitorwindow",
                             self.checkBox_showMonitorWindow.isChecked())
        app.settings.setint("frontend", "monitorfullspeed",
                            self.spinBox_monitorFullSpeed.value())
        app.settings.setbool("frontend", "watchclipboard",
                             self.checkBox_watchClipboard.isChecked())
        app.settings.set("frontend", "watchpattern",
                         self.plaintext_watchPattern.toPlainText())

        if self.group_etmStartWhen.isEnabled():
            startEtmWhen = self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton())
            app.adapterManager[0].startEtmWhen = startEtmWhen

        app.settings.save()

        if self.tab_mount.isEnabled():
            app.adapterManager[0].mountsFaker.mounts = self.newMounts
        app.applySettings.emit()
        super().accept()

    @property
    def newMounts(self):
        return list(map(lambda row: self.table_mounts.item(row, 1).text(),
                        range(self.table_mounts.rowCount())))

    @pyqtSlot()
    def setupETM(self):
        # fill values
        adapter = app.adapterManager[0]
        settings = adapter.backendSettings
        etmRunning = adapter.etmPid != 0
        if etmRunning and settings.initialized:
            self.spinBox_dSpeedLimit.setValue(settings.downloadSpeedLimit)
            self.spinBox_uSpeedLimit.setValue(settings.uploadSpeedLimit)
            self.spinBox_maxRunningTasksNum.setValue(settings.maxRunTaskNumber)

            # connect signals
            self.accepted.connect(self.saveETM)
        else:
            self.spinBox_dSpeedLimit.setEnabled(False)
            self.spinBox_uSpeedLimit.setEnabled(False)
            self.spinBox_maxRunningTasksNum.setEnabled(False)

    @pyqtSlot()
    def saveETM(self):
        adapter = app.adapterManager[0]
        adapter.do_applySettings({
            "downloadSpeedLimit": self.spinBox_dSpeedLimit.value(),
            "uploadSpeedLimit": self.spinBox_uSpeedLimit.value(),
            "maxRunTaskNumber": self.spinBox_maxRunningTasksNum.value(),
        })
Beispiel #22
0
class SettingsDialog(QDialog, Ui_Dialog):
    def __init__(self, parent):
        super().__init__(parent)
        self.setWindowModality(Qt.WindowModal)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.mainWin = parent
        self.setupUi(self)

        self.lineEdit_loginUsername.setText(self.settings.get("account", "username"))
        self.lineEdit_loginPassword.setText(self.settings.get("account", "password"))
        self.checkBox_autoLogin.setChecked(self.settings.getbool("account", "autologin"))

        self.checkBox_enableDevelopersTools.setChecked(
            self.settings.getbool("frontend", "enabledeveloperstools"))
        self.checkBox_allowFlash.setChecked(self.settings.getbool("frontend", "allowflash"))
        self.checkBox_minimizeToSystray.setChecked(self.settings.getbool("frontend", "minimizetosystray"))
        self.checkBox_closeToMinimize.setChecked(self.settings.getbool("frontend", "closetominimize"))
        self.checkBox_popNotifications.setChecked(self.settings.getbool("frontend", "popnotifications"))
        self.checkBox_notifyBySound.setChecked(self.settings.getbool("frontend", "notifybysound"))
        self.checkBox_showMonitorWindow.setChecked(self.settings.getbool("frontend", "showmonitorwindow"))
        self.spinBox_monitorFullSpeed.setValue(self.settings.getint("frontend", "monitorfullspeed"))
        # clipboard related
        self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled)
        self.checkBox_watchClipboard.setChecked(self.settings.getbool("frontend", "watchclipboard"))
        self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState())
        self.plaintext_watchPattern.setPlainText(self.settings.get("frontend", "watchpattern"))

        from PyQt5.QtWidgets import QButtonGroup
        self.btngrp_etmStartWhen = QButtonGroup()
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3)
        self.btngrp_etmStartWhen.button(self.settings.getint("xwared", "startetmwhen")).setChecked(True)

        self.accepted.connect(self.writeSettings)

        self.btn_addMount.clicked.connect(self.slotAddMount)
        self.btn_removeMount.clicked.connect(self.slotRemoveMount)
        self.btn_refreshMount.clicked.connect(self.setupMounts)

        # Mounts
        self.setupMounts()

        # backend setting is a different thing!
        self.setupETM()

    # shorthand
    @property
    def settings(self):
        return self.mainWin.settings
    # shorthand ends

    @staticmethod
    def permissionCheck():
        import re
        ansiEscape = re.compile(r'\x1b[^m]*m')

        import subprocess
        with subprocess.Popen([constants.PERMISSIONCHECK], stdout = subprocess.PIPE, stderr = subprocess.PIPE) as proc:
            output = proc.stdout.read().decode("utf-8")
            output = ansiEscape.sub('', output)
            lines = output.split("\n")

        prevLine = None
        currMount = None
        result = {}
        for line in lines:
            if len(line.strip()) == 0:
                continue

            if all(map(lambda c: c == '=', line)):
                if currMount:
                    result[currMount] = result[currMount][:-1]

                result[prevLine] = []
                currMount = prevLine
                continue

            if currMount:
                if line != "正常。":
                    result[currMount].append(line)

            prevLine = line

        return result

    @pyqtSlot(int)
    def slotWatchClipboardToggled(self, state):
        # disable pattern settings, before
        # 1. complete patterns
        # 2. test glib key file compatibility
        self.plaintext_watchPattern.setReadOnly(True)
        self.plaintext_watchPattern.setEnabled(state)

    @pyqtSlot()
    def setupMounts(self):
        self.table_mounts.setRowCount(0)
        self.table_mounts.clearContents()

        PermissionError = self.permissionCheck()

        mountsMapping = self.mainWin.mountsFaker.getMountsMapping()
        for i, mount in enumerate(self.mainWin.mountsFaker.mounts):
            # mounts = ['/path/to/1', 'path/to/2', ...]
            self.table_mounts.insertRow(i)
            self.table_mounts.setItem(i, 0, QTableWidgetItem(mount))
            drive1 = chr(ord('C') + i) + ":" # the drive letter it should map to, by alphabetical order
            self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1))
            drive2 = mountsMapping.get(mount, "无") # the drive letter it actually is assigned to

            # check 1: permission
            errors = PermissionError.get(mount, ["无法获得检测权限。运行/opt/xware_desktop/permissioncheck查看原因。"])

            # check 2: mapping
            if drive1 != drive2:
                errors.append("警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format(actual = drive2, should = drive1))

            from PyQt5.Qt import Qt
            from PyQt5.QtGui import QBrush

            brush = QBrush()
            if errors:
                brush.setColor(Qt.red)
                errString = "\n".join(errors)
            else:
                brush.setColor(Qt.darkGreen)
                errString = "正常"
            errWidget = QTableWidgetItem(errString)
            errWidget.setForeground(brush)

            self.table_mounts.setItem(i, 2, errWidget)
            del brush, errWidget

        self.table_mounts.resizeColumnsToContents()

    @pyqtSlot()
    def slotAddMount(self):
        import os
        from PyQt5.QtWidgets import QFileDialog
        from PyQt5.Qt import Qt

        fileDialog = QFileDialog(self, Qt.Dialog)
        fileDialog.setFileMode(QFileDialog.Directory)
        fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
        fileDialog.setViewMode(QFileDialog.List)
        fileDialog.setDirectory(os.environ["HOME"])
        if (fileDialog.exec()):
            selected = fileDialog.selectedFiles()[0]
            if selected in self.newMounts:
                return
            row = self.table_mounts.rowCount()
            self.table_mounts.insertRow(row)
            self.table_mounts.setItem(row, 0, QTableWidgetItem(selected))
            self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加"))
            self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加"))

    @pyqtSlot()
    def slotRemoveMount(self):
        row = self.table_mounts.currentRow()
        self.table_mounts.removeRow(row)

    @pyqtSlot()
    def writeSettings(self):
        self.settings.set("account", "username", self.lineEdit_loginUsername.text())
        self.settings.set("account", "password", self.lineEdit_loginPassword.text())
        self.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked())

        self.settings.setbool("frontend", "enabledeveloperstools",
                                self.checkBox_enableDevelopersTools.isChecked())
        self.settings.setbool("frontend", "allowflash",
                                self.checkBox_allowFlash.isChecked())
        self.settings.setbool("frontend", "minimizetosystray",
                                self.checkBox_minimizeToSystray.isChecked())

        # A possible Qt bug
        # https://bugreports.qt-project.org/browse/QTBUG-37695
        self.settings.setbool("frontend", "closetominimize",
                                self.checkBox_closeToMinimize.isChecked())
        self.settings.setbool("frontend", "popnotifications",
                                self.checkBox_popNotifications.isChecked())
        self.settings.setbool("frontend", "notifybysound",
                                self.checkBox_notifyBySound.isChecked())

        self.settings.setbool("frontend", "showmonitorwindow",
                                self.checkBox_showMonitorWindow.isChecked())
        self.settings.setint("frontend", "monitorfullspeed",
                                self.spinBox_monitorFullSpeed.value())
        self.settings.setbool("frontend", "watchclipboard",
                                self.checkBox_watchClipboard.isChecked())
        # self.settings.set("frontend", "watchpattern",
        #                         self.plaintext_watchPattern.toPlainText())
        self.settings.setint("xwared", "startetmwhen",
                          self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton()))

        startETMWhen = self.settings.getint("xwared", "startetmwhen")
        if startETMWhen == 1:
            self.settings.setbool("xwared", "startetm", True)

        self.settings.save()

        self.mainWin.mountsFaker.setMounts(self.newMounts)
        self.settings.applySettings.emit()

    @property
    def newMounts(self):
        return list(map(lambda row: self.table_mounts.item(row, 0).text(),
                        range(self.table_mounts.rowCount())))

    @pyqtSlot()
    def setupETM(self):
        etmpy = self.mainWin.etmpy

        # fill values
        self.lineEdit_lcport.setText(etmpy.cfg.get("local_control.listen_port", "不可用"))

        etmSettings = etmpy.getSettings()
        if etmSettings:
            self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit)
            self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit)
            self.spinBox_maxRunningTasksNum.setValue(etmSettings.maxRunningTasksNum)

            # connect signals
            self.accepted.connect(self.saveETM)
        else:
            self.spinBox_dSpeedLimit.setEnabled(False)
            self.spinBox_uSpeedLimit.setEnabled(False)
            self.spinBox_maxRunningTasksNum.setEnabled(False)

    @pyqtSlot()
    def saveETM(self):
        import etmpy

        newsettings = etmpy.EtmSetting(dLimit = self.spinBox_dSpeedLimit.value(),
                                       uLimit = self.spinBox_uSpeedLimit.value(),
                                       maxRunningTasksNum = self.spinBox_maxRunningTasksNum.value())

        self.mainWin.etmpy.saveSettings(newsettings)
Beispiel #23
0
class SpectraModuleUI(QWidget):

    monoStartup = pyqtSignal()

    def __init__(self, cam_wi, status_bar, hardware_conf):
        super().__init__()

        self.CameraWI = cam_wi
        self.statusBar = status_bar

        self.ui_construct(hardware_conf)

    def init_parameters(self, param_set):
        frame = param_set['frameSet']
        stage = param_set['stagePos']
        laser = param_set['Laser']
        mono = param_set['MDR-3']
        andor = param_set['Andor']

        # Hardware parameter set
        self.x_pos.setText(str(stage['x']))
        self.y_pos.setText(str(stage['y']))
        self.z_pos.setText(str(stage['z']))
        self.step_val.setCurrentText(str(stage['step']))

        self.WLStart.setValue(mono['WL-start'])
        self.monoGridPos.setValue(mono['WL-pos'])
        self.monoCurrentPos.setText(str(mono['WL-pos']) + ' nm')
        self.monoGridSelect.setCurrentIndex(mono['grating-select'])
        self.monoStartup.emit()

        self.laserSelect.setCurrentIndex(laser['source-id'])

        # Frame parameter set
        self.frameRowSelect.setValue(frame['row'])
        self.frameColSelect.setValue(frame['column'])
        self.frameColSelect.setValue(frame['column'])

        self.rowBinning.setValue(frame['binning'])
        if frame['binningAvg']:
            self.avgBinning.setChecked(True)

        # self.XUnits.button(frame['x-axis']).setChecked(True)
        self.XUnits.button(frame['x-axis']).click()

        # self.YUnits.button(frame['y-axis']).setChecked(True)
        self.YUnits.button(frame['y-axis']).click()

        # Andor parameter set
        self.exposureTime.setValue(andor['exposure'])
        self.acquisitionMode.setCurrentIndex(andor['AcqMode']['mode'])
        self.mode_prm_enable(andor['AcqMode']['mode'])
        self.accumulationFrames.setValue(andor['AcqMode']['accumFrames'])
        self.accumulationCycle.setValue(andor['AcqMode']['accumCycle'])
        self.kineticSeries.setValue(andor['AcqMode']['kSeries'])
        self.kineticCycle.setValue(andor['AcqMode']['kCycle'])
        self.triggeringMode.setCurrentIndex(andor['trigMode'])
        self.readoutMode.setCurrentIndex(andor['readMode'])
        self.VSSpeed.setCurrentIndex(andor['VSSpeed'])
        self.VSAVoltage.setCurrentIndex(andor['VSAVoltage'])
        self.readoutRate.setCurrentIndex(andor['ADCRate'])
        self.preAmpGain.setCurrentIndex(andor['gain'])

    def mode_prm_enable(self, acq_mode):
        if acq_mode == 0:
            self.accumulationFrames.setEnabled(False)
            self.accumulationCycle.setEnabled(False)
            self.kineticSeries.setEnabled(False)
            self.kineticCycle.setEnabled(False)
        elif acq_mode == 1:
            self.accumulationFrames.setEnabled(True)
            self.accumulationCycle.setEnabled(True)
            self.kineticSeries.setEnabled(False)
            self.kineticCycle.setEnabled(False)
        elif acq_mode == 2:
            self.accumulationFrames.setEnabled(True)
            self.accumulationCycle.setEnabled(True)
            self.kineticSeries.setEnabled(True)
            self.kineticCycle.setEnabled(True)
        elif acq_mode == 4:
            self.accumulationFrames.setEnabled(False)
            self.accumulationCycle.setEnabled(True)
            self.kineticSeries.setEnabled(True)
            self.kineticCycle.setEnabled(False)

    def ui_construct(self, conf):
        # Main splitters
        topleft_frame = QFrame(self)
        topleft_frame.setFrameShape(QFrame.StyledPanel)

        topright_frame = QFrame(self)
        topright_frame.setFrameShape(QFrame.StyledPanel)

        bottom_frame = QFrame(self)
        bottom_frame.setFrameShape(QFrame.StyledPanel)

        splitter1 = QSplitter(Qt.Horizontal)
        splitter1.addWidget(topleft_frame)
        splitter1.addWidget(topright_frame)
        splitter1.setSizes((250, 100))
        splitter1.setStretchFactor(0, 0)
        splitter1.setStretchFactor(1, 1)

        splitter2 = QSplitter(Qt.Vertical)
        splitter2.addWidget(splitter1)
        splitter2.addWidget(bottom_frame)
        splitter2.setSizes((100, 200))
        splitter2.setStretchFactor(0, 1)
        splitter2.setStretchFactor(1, 0)

        main_lay = QVBoxLayout(self)
        main_lay.addWidget(splitter2)

        view_area = QTabWidget(self)
        view_area.setTabPosition(QTabWidget.West)
        ccd = QFrame(self)
        view_area.addTab(ccd, "Spectra acquisition")
        view_area.addTab(self.CameraWI, "Camera")

        view_area_lay = QVBoxLayout(topright_frame)
        view_area_lay.addWidget(view_area)

        # --- Controls frame ---

        self.monoGridPos = QDoubleSpinBox(self)
        self.monoGridPos.setRange(200.0, 1000.0)
        self.monoGridPos.setSingleStep(0.1)
        self.monoGridPos.setDecimals(1)
        self.monoSetPos = QPushButton('Set')
        self.monoSetPos.setMinimumSize(90, 30)
        self.monoCalibrate = QPushButton('Calibration')
        self.monoCalibrate.setMinimumSize(90, 30)
        self.monoStop = QPushButton('Stop')
        self.monoStop.setMinimumSize(90, 30)
        self.monoCurrentPos = QLabel('500.00 nm')
        mono_pos_lbl = QLabel('Current position: ')
        self.monoGridSelect = QComboBox(self)
        self.monoGridSelect.addItems(['300 g/mm', '600 g/mm'])
        mono_grid_lbl = QLabel('Grating: ')

        self.laserSelect = QComboBox(self)
        self.laserSelect.addItems(
            ['Laser 405 nm', 'Laser 450 nm', 'LED 370 nm', 'LED 430 nm'])
        self.laserOn = QPushButton('Connect')
        self.laserOff = QPushButton('Disconnect')
        self.laserOn.setMinimumSize(110, 30)
        self.laserOff.setMinimumSize(110, 30)
        self.laserConn = QLabel('Off', self)
        self.laserStat = QLabel('0 mW', self)
        self.laserPower = QSlider(Qt.Vertical)
        laser_select_lbl = QLabel('Source: ', self)
        laser_conn_lbl = QLabel('Connection: ', self)
        laser_stat_lbl = QLabel('Power: ', self)

        self.x_up = QPushButton('X+')
        self.x_down = QPushButton('X-')
        self.y_up = QPushButton('Y+')
        self.y_down = QPushButton('Y-')
        self.z_up = QPushButton('Z+')
        self.z_down = QPushButton('Z-')
        self.stop_move = QPushButton('Stop')
        self.step_val = QComboBox(self)
        self.step_val.setEditable(True)
        self.step_val.addItems([
            '1', '2', '5', '10', '20', '50', '100', '200', '500', '1000',
            '2000', '5000'
        ])
        self.step_val.setValidator(QIntValidator(1, 10000))
        step_lbl = QLabel('Step size: ', self)
        self.distance_lbl = QLabel('Distance: 0.05um', self)
        self.x_up.setMinimumSize(85, 30)
        self.x_down.setMinimumSize(85, 30)
        self.x_down.setMinimumSize(85, 30)
        self.y_up.setMinimumSize(85, 30)
        self.y_down.setMinimumSize(85, 30)
        self.z_up.setMinimumSize(85, 30)
        self.z_down.setMinimumSize(85, 30)
        self.stop_move.setMinimumSize(85, 30)

        self.x_pos = QTableWidgetItem()
        self.x_pos.setTextAlignment(Qt.AlignCenter)
        self.y_pos = QTableWidgetItem()
        self.y_pos.setTextAlignment(Qt.AlignCenter)
        self.z_pos = QTableWidgetItem()
        self.z_pos.setTextAlignment(Qt.AlignCenter)

        self.acquire_btn = QPushButton('Acquire')
        self.acquire_btn.setFixedSize(120, 60)

        stage_coordinates = QTableWidget(3, 1)
        stage_coordinates.setEditTriggers(QAbstractItemView.NoEditTriggers)
        stage_coordinates.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        stage_coordinates.verticalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        stage_coordinates.setStyleSheet("border: 0")
        stage_coordinates.setHorizontalHeaderLabels(['Position'])
        stage_coordinates.setVerticalHeaderLabels(['X', 'Y', 'Z'])
        stage_coordinates.setItem(0, 0, self.x_pos)
        stage_coordinates.setItem(1, 0, self.y_pos)
        stage_coordinates.setItem(2, 0, self.z_pos)

        mono_control_group = QGroupBox('Monochromator')
        mono_control_group.setAlignment(Qt.AlignCenter)
        mono_control_lay = QGridLayout(mono_control_group)
        mono_control_lay.addWidget(self.monoGridPos, 0, 0)
        mono_control_lay.addWidget(self.monoSetPos, 0, 1)
        mono_control_lay.addWidget(self.monoCalibrate, 1, 0)
        mono_control_lay.addWidget(self.monoStop, 1, 1)
        mono_control_lay.addWidget(mono_pos_lbl, 2, 0)
        mono_control_lay.addWidget(self.monoCurrentPos, 2, 1)
        mono_control_lay.addWidget(mono_grid_lbl, 3, 0)
        mono_control_lay.addWidget(self.monoGridSelect, 3, 1)

        light_source_group = QGroupBox('Light source')
        light_source_group.setAlignment(Qt.AlignCenter)
        light_source_lay = QGridLayout(light_source_group)
        light_source_lay.addWidget(laser_select_lbl, 0, 0)
        light_source_lay.addWidget(self.laserSelect, 0, 1)
        light_source_lay.addWidget(self.laserOn, 1, 0)
        light_source_lay.addWidget(self.laserOff, 1, 1)
        light_source_lay.addWidget(laser_conn_lbl, 2, 0)
        light_source_lay.addWidget(self.laserConn, 2, 1)
        light_source_lay.addWidget(laser_stat_lbl, 3, 0)
        light_source_lay.addWidget(self.laserStat, 3, 1)
        light_source_lay.addWidget(self.laserPower, 0, 3, 4, 1)
        light_source_lay.setColumnMinimumWidth(2, 20)

        stage_pos_group = QGroupBox('Stage position')
        stage_pos_group.setAlignment(Qt.AlignCenter)
        stage_pos_lay = QGridLayout(stage_pos_group)
        stage_pos_lay.addWidget(self.x_up, 1, 2)
        stage_pos_lay.addWidget(self.x_down, 1, 0)
        stage_pos_lay.addWidget(self.y_up, 0, 1)
        stage_pos_lay.addWidget(self.y_down, 2, 1)
        stage_pos_lay.addWidget(self.z_up, 0, 3)
        stage_pos_lay.addWidget(self.z_down, 2, 3)
        stage_pos_lay.addWidget(self.stop_move, 1, 1)
        stage_pos_lay.addWidget(step_lbl, 3, 0)
        stage_pos_lay.addWidget(self.step_val, 3, 1)
        stage_pos_lay.addWidget(self.distance_lbl, 3, 2, 1, 2)
        stage_pos_lay.setColumnMinimumWidth(4, 20)
        stage_pos_lay.addWidget(stage_coordinates, 0, 5, 4, 1)

        acquire_btns_group = QFrame(self)
        acquire_btns_lay = QHBoxLayout(acquire_btns_group)
        acquire_btns_lay.addWidget(self.acquire_btn)

        action_btns_lay = QHBoxLayout(bottom_frame)
        action_btns_lay.addWidget(mono_control_group, 3)
        action_btns_lay.addWidget(light_source_group, 3)
        action_btns_lay.addWidget(stage_pos_group, 6)
        action_btns_lay.addWidget(acquire_btns_group, 3)
        action_btns_lay.setSpacing(20)

        # --- CCD Frame Layout ---

        self.CCDFrame = PgGraphicsView(self, aspect_locked=False)
        self.CCDFrame.setMinimumSize(512, 128)
        self.CCDFrame.vb.setLimits(xMin=0,
                                   xMax=conf['CCD-w'] - 1,
                                   yMin=0,
                                   yMax=conf['CCD-h'] - 1)
        self.vLine = CrossLine(angle=90, bounds=(0.5, 1023.5))
        self.hLine = CrossLine(angle=0, bounds=(0.5, 255.5))
        self.CCDFrame.vb.addItem(self.vLine)
        self.CCDFrame.vb.addItem(self.hLine)

        self.spectrum = PgPlotWidget(self, w='row')
        self.spectrum.plotItem.setLabels(left='Intensity')
        self.spectrum.vb.setYRange(0, 40000)
        self.spectrumCursor = CrossCursor()
        self.cursorPosLbl = pg.TextItem(text="X = 0, Y = 0",
                                        anchor=(-5, -1),
                                        color=pg.mkColor("#99999988"))
        self.cursorPosLbl.setParentItem(self.spectrum.vb)
        self.spectrum.vb.addItem(self.spectrumCursor)

        self.frameSection = PgPlotWidget(self, w='col')
        # self.frameSection.setLabels(right='Row')
        self.frameSection.vb.setYRange(0, conf['CCD-h'] - 1)
        self.frameSection.vb.setLimits(yMin=0, yMax=conf['CCD-h'] - 1)
        # self.frameSectionCurve = self.frameSection.plot(pen='y')
        self.frameSectionCursor = CrossCursor()
        self.frameSection.addItem(self.frameSectionCursor)

        self.frameRowSelect = QSpinBox(self)
        self.frameRowSelect.setRange(1, conf['CCD-h'])
        self.frameColSelect = QSpinBox(self)
        self.frameColSelect.setRange(1, conf['CCD-w'])

        y_radio0 = QRadioButton('Counts')
        y_radio0.setChecked(True)
        y_radio1 = QRadioButton('Counts norm.')
        self.YUnits = QButtonGroup(self)
        self.YUnits.addButton(y_radio0, id=0)
        self.YUnits.addButton(y_radio1, id=1)

        x_radio0 = QRadioButton('nm')
        x_radio0.setChecked(True)
        x_radio1 = QRadioButton('eV')
        x_radio2 = QRadioButton('pixel number')
        self.XUnits = QButtonGroup(self)
        self.XUnits.addButton(x_radio0, id=0)
        self.XUnits.addButton(x_radio1, id=1)
        self.XUnits.addButton(x_radio2, id=2)
        self.XUnits.button(0).setChecked(True)

        self.rowBinning = QSpinBox(self)
        self.rowBinning.setRange(1, 256)
        self.avgBinning = QCheckBox('Average value')
        row_binning_lbl = QLabel('Binning', self)

        row_select_group = QGroupBox('Row/Column')
        row_select_group.setAlignment(Qt.AlignCenter)
        row_select_lay = QHBoxLayout(row_select_group)
        row_select_lay.addWidget(self.frameRowSelect)
        row_select_lay.addWidget(self.frameColSelect)

        y_units_group = QGroupBox("Y-axis")
        y_units_group.setAlignment(Qt.AlignCenter)
        y_units_lay = QVBoxLayout(y_units_group)
        y_units_lay.addWidget(y_radio0)
        y_units_lay.addWidget(y_radio1)

        x_units_group = QGroupBox("X-axis")
        x_units_group.setAlignment(Qt.AlignCenter)
        x_units_lay = QVBoxLayout(x_units_group)
        x_units_lay.addWidget(x_radio0)
        x_units_lay.addWidget(x_radio1)
        x_units_lay.addWidget(x_radio2)

        row_binning_group = QGroupBox()
        row_binning_group.setAlignment(Qt.AlignCenter)
        row_binning_lay = QGridLayout(row_binning_group)
        row_binning_lay.addWidget(row_binning_lbl, 0, 0)
        row_binning_lay.addWidget(self.rowBinning, 0, 1)
        row_binning_lay.addWidget(self.avgBinning, 1, 0, 1, 2)

        frame_param = QFrame()
        frame_param_lay = QVBoxLayout(frame_param)
        frame_param_lay.setSpacing(0)
        frame_param_lay.addWidget(row_select_group)
        frame_param_lay.addWidget(y_units_group)
        frame_param_lay.addWidget(x_units_group)
        frame_param_lay.addWidget(row_binning_group)

        ccd_lay = QGridLayout(ccd)
        ccd_lay.setRowStretch(0, 2)
        ccd_lay.setRowStretch(1, 3)
        ccd_lay.setColumnStretch(0, 1)
        ccd_lay.setColumnStretch(1, 6)
        ccd_lay.addWidget(self.CCDFrame, 0, 1)
        ccd_lay.addWidget(self.spectrum, 1, 1)
        ccd_lay.addWidget(self.frameSection, 0, 0)
        ccd_lay.addWidget(frame_param, 1, 0)

        # --- Experiment Details, Andor Camera Settings ---

        self.WLStart = QDoubleSpinBox(self)
        self.WLStart.setRange(200.0, 1000.0)
        self.WLStart.setSingleStep(0.1)
        self.WLStart.setDecimals(1)
        self.WLEnd = QLineEdit(self)
        self.WLEnd.setReadOnly(True)
        self.WLEnd_dec = QPushButton('<')
        self.WLEnd_inc = QPushButton('>')
        self.WLEnd_dec.setStyleSheet('QPushButton {min-width: 20px;}')
        self.WLEnd_inc.setStyleSheet('QPushButton {min-width: 20px;}')
        WL_range_lbl = QLabel('—')

        WL_range_group = QGroupBox("Wavelength range")
        WL_range_lay = QHBoxLayout(WL_range_group)
        WL_range_lay.addWidget(self.WLStart, 5)
        WL_range_lay.addWidget(WL_range_lbl, 1)
        WL_range_lay.addWidget(self.WLEnd, 5)
        WL_range_lay.addWidget(self.WLEnd_dec, 1)
        WL_range_lay.addWidget(self.WLEnd_inc, 1)

        self.exposureTime = QDoubleSpinBox(self)
        self.exposureTime.setRange(0.01, 1000.0)
        self.exposureTime.setDecimals(2)
        # self.exposureTime.setStepType(QDoubleSpinBox.AdaptiveDecimalStepType)
        exp_time_lbl = QLabel('Exposure time (sec)')

        self.acquisitionMode = QComboBox(self)
        self.acquisitionMode.addItems([
            'Single', 'Accumulate', 'Kinetic', 'Photon Count', 'Fast Kinetic'
        ])
        self.acquisitionMode.model().item(3).setEnabled(False)
        self.accumulationFrames = QSpinBox(self)
        self.accumulationFrames.setRange(1, 50)
        self.accumulationCycle = QDoubleSpinBox(self)
        self.accumulationCycle.setRange(0.01, 1000.0)
        self.accumulationCycle.setSingleStep(1)
        self.accumulationCycle.setDecimals(2)
        self.kineticSeries = QSpinBox(self)
        self.kineticSeries.setRange(1, 50)
        self.kineticCycle = QDoubleSpinBox(self)
        self.kineticCycle.setRange(0.01, 1000.0)
        self.kineticCycle.setSingleStep(1)
        self.kineticCycle.setDecimals(2)
        acq_mode_lbl = QLabel('Acquisition Mode', self)
        accum_frames_lbl = QLabel('Accumulation Frames')
        accum_cycle_lbl = QLabel('Accumulation Cycle')
        kinetic_series_lbl = QLabel('Kinetic Series')
        kinetic_cycle_lbl = QLabel('Kinetic Cycle Time')

        self.triggeringMode = QComboBox(self)
        self.triggeringMode.addItems(
            ['Internal', 'External', 'Fast External', 'External Start'])
        self.triggeringMode.model().item(2).setEnabled(False)
        self.readoutMode = QComboBox(self)
        self.readoutMode.addItems(
            ['Image', 'Single-Track', 'Multi-Track', 'FVB'])
        self.readoutMode.model().item(1).setEnabled(False)
        self.readoutMode.model().item(2).setEnabled(False)
        self.readoutMode.model().item(3).setEnabled(False)
        trig_mode_lbl = QLabel('Triggering Mode', self)
        read_mode_lbl = QLabel('Readout Mode', self)

        self.readoutRate = QComboBox(self)
        self.readoutRate.addItems(
            ['50kHz at 16-bit', '1MHz at 16-bit', '3MHz at 16-bit'])
        self.preAmpGain = QComboBox(self)
        self.preAmpGain.addItems(['1x', '2x', '4x'])
        readout_rate_lbl = QLabel('Readout Rate')
        preamp_gain_lbl = QLabel('Pre-Amp Gain')

        self.VSSpeed = QComboBox(self)
        self.VSSpeed.addItems([
            '12.9', '25.7', '51.3', '76.9', '102.5', '128.1', '153.7', '179.3'
        ])
        self.VSAVoltage = QComboBox(self)
        self.VSAVoltage.addItems(['Normal', '+1'])
        self.VSAVoltage.model().item(1).setEnabled(False)
        vs_speed_lbl = QLabel('VShift speed (usec)')
        vsa_voltage_lbl = QLabel('VShift Amp Voltage')

        cam_settings_lay = QVBoxLayout(topleft_frame)
        cam_settings_lay.setSpacing(10)

        cam_exposure_group = QGroupBox("Exposition")
        cam_exposure_lay = QGridLayout(cam_exposure_group)
        cam_exposure_lay.addWidget(exp_time_lbl, 0, 0)
        cam_exposure_lay.addWidget(self.exposureTime, 0, 1)

        cam_timing_group = QGroupBox("Acquisition timings")
        cam_timing_lay = QGridLayout(cam_timing_group)
        cam_timing_lay.addWidget(acq_mode_lbl, 0, 0)
        cam_timing_lay.addWidget(self.acquisitionMode, 0, 1)
        cam_timing_lay.addWidget(accum_frames_lbl, 1, 0)
        cam_timing_lay.addWidget(self.accumulationFrames, 1, 1)
        cam_timing_lay.addWidget(accum_cycle_lbl, 2, 0)
        cam_timing_lay.addWidget(self.accumulationCycle, 2, 1)
        cam_timing_lay.addWidget(kinetic_series_lbl, 3, 0)
        cam_timing_lay.addWidget(self.kineticSeries, 3, 1)
        cam_timing_lay.addWidget(kinetic_cycle_lbl, 4, 0)
        cam_timing_lay.addWidget(self.kineticCycle, 4, 1)

        cam_mode_group = QGroupBox("Mode")
        cam_mode_lay = QGridLayout(cam_mode_group)
        cam_mode_lay.addWidget(trig_mode_lbl, 0, 0)
        cam_mode_lay.addWidget(self.triggeringMode, 0, 1)
        cam_mode_lay.addWidget(read_mode_lbl, 1, 0)
        cam_mode_lay.addWidget(self.readoutMode, 1, 1)

        cam_readout_group = QGroupBox("Readout")
        cam_readout_lay = QGridLayout(cam_readout_group)
        cam_readout_lay.addWidget(readout_rate_lbl, 0, 0)
        cam_readout_lay.addWidget(self.readoutRate, 0, 1)
        cam_readout_lay.addWidget(preamp_gain_lbl, 1, 0)
        cam_readout_lay.addWidget(self.preAmpGain, 1, 1)
        cam_readout_lay.addWidget(vs_speed_lbl, 2, 0)
        cam_readout_lay.addWidget(self.VSSpeed, 2, 1)
        cam_readout_lay.addWidget(vsa_voltage_lbl, 3, 0)
        cam_readout_lay.addWidget(self.VSAVoltage, 3, 1)

        cam_settings_lay.addWidget(WL_range_group)
        cam_settings_lay.addWidget(cam_exposure_group)
        cam_settings_lay.addWidget(cam_timing_group)
        cam_settings_lay.addWidget(cam_mode_group)
        cam_settings_lay.addWidget(cam_readout_group)
Beispiel #24
0
 def create_rows(self, layout, sarea):
     u"""Build the rows of the dialog box"""
     play_button_group = QButtonGroup(sarea)
     old_play_button_group = QButtonGroup(sarea)
     for num, entry in enumerate(self.entries_list, 2):
         tt_text = self.build_text_help_label(entry)
         ico_label = QLabel('', sarea)
         ico_label.setToolTip(tt_text)
         if entry.icon:
             ico_label.setPixmap(QPixmap.fromImage(entry.icon))
         layout.addWidget(ico_label, num, 0)
         tt_label = QLabel(entry.display_word, sarea)
         tt_label.setToolTip(tt_text)
         layout.addWidget(tt_label, num, 1)
         if self.hide_text:
             tt_label.hide()
         # Play button.
         t_play_button = QPushButton(sarea)
         play_button_group.addButton(t_play_button, num-2)
         t_play_button.setToolTip(self.play_help)
         t_play_button.setIcon(QIcon(os.path.join(icons_dir, 'play.png')))
         layout.addWidget(t_play_button, num, self.play_column)
         if self.note[entry.audio_field_name]:
             t_play_old_button = QPushButton(sarea)
             old_play_button_group.addButton(t_play_old_button, num-2)
             t_play_old_button.setIcon(
                 QIcon(os.path.join(icons_dir, 'play.png')))
             if not self.hide_text:
                 t_play_old_button.setToolTip(
                     self.note[entry.audio_field_name])
             else:
                 t_play_old_button.setToolTip(self.play_old_help_short)
             layout.addWidget(t_play_old_button, num, self.play_old_column)
         else:
             dummy_label = QLabel('', sarea)
             dummy_label.setToolTip(self.play_old_empty_line_help)
             layout.addWidget(dummy_label, num, self.play_old_column)
         # The group where we later look what to do:
         t_button_group = QButtonGroup(sarea)
         t_button_group.setExclusive(True)
         # Now the four buttons
         t_add_button = QPushButton(sarea)
         t_add_button.setCheckable(True)
         t_add_button.setFlat(True)
         t_add_button.setToolTip(self.add_help_text_short)
         t_add_button.setIcon(QIcon(os.path.join(icons_dir, 'add.png')))
         layout.addWidget(t_add_button, num, self.add_column)
         t_button_group.addButton(t_add_button, Action.Add)
         t_keep_button = QPushButton(sarea)
         t_keep_button.setCheckable(True)
         t_keep_button.setFlat(True)
         t_keep_button.setToolTip(self.keep_help_text_short)
         t_keep_button.setIcon(QIcon(os.path.join(icons_dir, 'keep.png')))
         layout.addWidget(t_keep_button, num, self.keep_column)
         t_button_group.addButton(t_keep_button, Action.Keep)
         t_delete_button = QPushButton(sarea)
         t_delete_button.setCheckable(True)
         t_delete_button.setFlat(True)
         t_delete_button.setToolTip(self.delete_help_text_short)
         t_delete_button.setIcon(
             QIcon(os.path.join(icons_dir, 'delete.png')))
         layout.addWidget(t_delete_button, num, self.delete_column)
         t_button_group.addButton(t_delete_button,  Action.Delete)
         t_blacklist_button = QPushButton(sarea)
         t_blacklist_button.setCheckable(True)
         t_blacklist_button.setFlat(True)
         t_blacklist_button.setToolTip(self.blacklist_help_text_short)
         t_blacklist_button.setIcon(
             QIcon(os.path.join(icons_dir, 'blacklist.png')))
         if entry.entry_hash:
             layout.addWidget(
                 t_blacklist_button, num, self.blacklist_column)
         else:
             t_blacklist_button.hide()
             dummy_label_bl = QLabel('', sarea)
             dummy_label_bl.setToolTip(self.blacklist_empty_line_help)
             layout.addWidget(dummy_label_bl, num, self.blacklist_column)
         t_button_group.button(entry.action).setChecked(True)
         # New: check a button based on how good the downloader is.
         t_button_group.addButton(t_blacklist_button, Action.Blacklist)
         self.buttons_groups.append(t_button_group)
     play_button_group.buttonClicked.connect(
         lambda button: play(
             self.entries_list[play_button_group.id(button)].file_path))
     # N.B.: anki.sound.play() plays files from anywhere, not just
     # from the colection.media folder. We should be good,
     # here. (This behaviour may be a security risk, idk.)
     old_play_button_group.buttonClicked.connect(
         lambda button: playFromText(
             self.note[
                 self.entries_list[
                     old_play_button_group.id(button)].audio_field_name]))
Beispiel #25
0
class SettingsDialog(QDialog, Ui_Dialog):
    def __init__(self, parent):
        super().__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setupUi(self)

        self.lineEdit_loginUsername.setText(
            app.settings.get("account", "username"))
        self.lineEdit_loginPassword.setText(
            app.settings.get("account", "password"))
        self.checkBox_autoLogin.setChecked(
            app.settings.getbool("account", "autologin"))
        self.checkBox_autoStartFrontend.setChecked(
            self.doesAutoStartFileExists())

        self.checkBox_enableDevelopersTools.setChecked(
            app.settings.getbool("frontend", "enabledeveloperstools"))
        self.checkBox_allowFlash.setChecked(
            app.settings.getbool("frontend", "allowflash"))
        self.checkBox_minimizeToSystray.setChecked(
            app.settings.getbool("frontend", "minimizetosystray"))
        self.checkBox_closeToMinimize.setChecked(
            app.settings.getbool("frontend", "closetominimize"))
        self.checkBox_popNotifications.setChecked(
            app.settings.getbool("frontend", "popnotifications"))
        self.checkBox_notifyBySound.setChecked(
            app.settings.getbool("frontend", "notifybysound"))
        self.checkBox_showMonitorWindow.setChecked(
            app.settings.getbool("frontend", "showmonitorwindow"))
        self.spinBox_monitorFullSpeed.setValue(
            app.settings.getint("frontend", "monitorfullspeed"))
        # clipboard related
        self.checkBox_watchClipboard.stateChanged.connect(
            self.slotWatchClipboardToggled)
        self.checkBox_watchClipboard.setChecked(
            app.settings.getbool("frontend", "watchclipboard"))
        self.slotWatchClipboardToggled(
            self.checkBox_watchClipboard.checkState())
        self.plaintext_watchPattern.setPlainText(
            app.settings.get("frontend", "watchpattern"))

        self.btngrp_etmStartWhen = QButtonGroup()
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3)

        try:
            startEtmWhen = callXwaredInterface("getStartEtmWhen")
            self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True)
        except SocketDoesntExist:
            self.group_etmStartWhen.setEnabled(False)

        self.btn_addMount.clicked.connect(self.slotAddMount)
        self.btn_removeMount.clicked.connect(self.slotRemoveMount)
        self.btn_refreshMount.clicked.connect(self.setupMounts)

        # Mounts
        self.setupMounts()

        # backend setting is a different thing!
        self.setupETM()

    @staticmethod
    def doesAutoStartFileExists():
        return os.path.lexists(constants.FRONTEND_AUTOSTART_FILE)

    @pyqtSlot(int)
    def slotWatchClipboardToggled(self, state):
        # disable pattern settings, before
        # 1. complete patterns
        # 2. test glib key file compatibility
        self.plaintext_watchPattern.setReadOnly(True)
        self.plaintext_watchPattern.setEnabled(state)

    @pyqtSlot()
    def setupMounts(self):
        self.table_mounts.setRowCount(0)
        self.table_mounts.clearContents()

        permissionCheckResult = app.mountsFaker.permissionCheck()
        permissionCheckFailed = [
            "无法获得检测权限。运行{}查看原因。".format(constants.PERMISSIONCHECK)
        ]

        mountsMapping = app.mountsFaker.getMountsMapping()
        for i, mount in enumerate(app.mountsFaker.mounts):
            # mounts = ['/path/to/1', 'path/to/2', ...]
            self.table_mounts.insertRow(i)
            self.table_mounts.setItem(i, 0, QTableWidgetItem(mount))
            # drive1: the drive letter it should map to, by alphabetical order
            drive1 = chr(ord('C') + i) + ":"
            self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1))
            # drive2: the drive letter it actually is assigned to
            drive2 = mountsMapping.get(mount, "无")

            # check 1: permission
            errors = permissionCheckResult.get(mount, permissionCheckFailed)

            # check 2: mapping
            if drive1 != drive2:
                errors.append(
                    "警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format(
                        actual=drive2, should=drive1))

            brush = QBrush()
            if errors:
                brush.setColor(Qt.red)
                errString = "\n".join(errors)
            else:
                brush.setColor(Qt.darkGreen)
                errString = "正常"
            errWidget = QTableWidgetItem(errString)
            errWidget.setForeground(brush)

            self.table_mounts.setItem(i, 2, errWidget)
            del brush, errWidget

        self.table_mounts.resizeColumnsToContents()

    @pyqtSlot()
    def slotAddMount(self):
        fileDialog = QFileDialog(self, Qt.Dialog)
        fileDialog.setFileMode(QFileDialog.Directory)
        fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
        fileDialog.setViewMode(QFileDialog.List)
        fileDialog.setDirectory(os.environ["HOME"])
        if fileDialog.exec():
            selected = fileDialog.selectedFiles()[0]
            if selected in self.newMounts:
                return
            row = self.table_mounts.rowCount()
            self.table_mounts.insertRow(row)
            self.table_mounts.setItem(row, 0, QTableWidgetItem(selected))
            self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加"))
            self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加"))

    @pyqtSlot()
    def slotRemoveMount(self):
        row = self.table_mounts.currentRow()
        self.table_mounts.removeRow(row)

    @pyqtSlot()
    def accept(self):
        app.settings.set("account", "username",
                         self.lineEdit_loginUsername.text())
        app.settings.set("account", "password",
                         self.lineEdit_loginPassword.text())
        app.settings.setbool("account", "autologin",
                             self.checkBox_autoLogin.isChecked())
        doesAutoStartFileExists = self.doesAutoStartFileExists()
        if self.checkBox_autoStartFrontend.isChecked(
        ) and not doesAutoStartFileExists:
            # mkdir if autostart dir doesn't exist
            try:
                os.mkdir(os.path.dirname(constants.FRONTEND_AUTOSTART_FILE))
            except OSError:
                pass  # already exists
            os.symlink(constants.DESKTOP_FILE_LOCATION,
                       constants.FRONTEND_AUTOSTART_FILE)
        elif (not self.checkBox_autoStartFrontend.isChecked()
              ) and doesAutoStartFileExists:
            os.remove(constants.FRONTEND_AUTOSTART_FILE)

        app.settings.setbool("frontend", "enabledeveloperstools",
                             self.checkBox_enableDevelopersTools.isChecked())
        app.settings.setbool("frontend", "allowflash",
                             self.checkBox_allowFlash.isChecked())
        app.settings.setbool("frontend", "minimizetosystray",
                             self.checkBox_minimizeToSystray.isChecked())

        # A possible Qt bug
        # https://bugreports.qt-project.org/browse/QTBUG-37695
        app.settings.setbool("frontend", "closetominimize",
                             self.checkBox_closeToMinimize.isChecked())
        app.settings.setbool("frontend", "popnotifications",
                             self.checkBox_popNotifications.isChecked())
        app.settings.setbool("frontend", "notifybysound",
                             self.checkBox_notifyBySound.isChecked())

        app.settings.setbool("frontend", "showmonitorwindow",
                             self.checkBox_showMonitorWindow.isChecked())
        app.settings.setint("frontend", "monitorfullspeed",
                            self.spinBox_monitorFullSpeed.value())
        app.settings.setbool("frontend", "watchclipboard",
                             self.checkBox_watchClipboard.isChecked())
        # app.settings.set("frontend", "watchpattern",
        #                         self.plaintext_watchPattern.toPlainText())

        if self.group_etmStartWhen.isEnabled():
            startEtmWhen = self.btngrp_etmStartWhen.id(
                self.btngrp_etmStartWhen.checkedButton())
            try:
                callXwaredInterface("setStartEtmWhen", startEtmWhen)
            except SocketDoesntExist:
                QMessageBox.warning(
                    None, "Xware Desktop",
                    "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()),
                    QMessageBox.Ok, QMessageBox.Ok)

        app.settings.save()

        app.mountsFaker.mounts = self.newMounts
        app.settings.applySettings.emit()
        super().accept()

    @property
    def newMounts(self):
        return list(
            map(lambda row: self.table_mounts.item(row, 0).text(),
                range(self.table_mounts.rowCount())))

    @pyqtSlot()
    def setupETM(self):
        # fill values
        lcPort = app.xwaredpy.lcPort
        self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用")

        etmSettings = app.etmpy.getSettings()
        if etmSettings:
            self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit)
            self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit)
            self.spinBox_maxRunningTasksNum.setValue(
                etmSettings.maxRunningTasksNum)

            # connect signals
            self.accepted.connect(self.saveETM)
        else:
            self.spinBox_dSpeedLimit.setEnabled(False)
            self.spinBox_uSpeedLimit.setEnabled(False)
            self.spinBox_maxRunningTasksNum.setEnabled(False)

    @pyqtSlot()
    def saveETM(self):
        newsettings = EtmSetting(
            dLimit=self.spinBox_dSpeedLimit.value(),
            uLimit=self.spinBox_uSpeedLimit.value(),
            maxRunningTasksNum=self.spinBox_maxRunningTasksNum.value())

        app.etmpy.saveSettings(newsettings)
Beispiel #26
0
class ToolBar(QWidget):
    mouseEntered = pyqtSignal()
    mouseLeft = pyqtSignal()

    toolChanged = pyqtSignal(str)
    primaryInkChanged = pyqtSignal(str)
    secondaryInkChanged = pyqtSignal(str)

    def __init__(self):

        super(ToolBar, self).__init__()

        self.setAttribute(Qt.WA_StaticContents)
        self.setAttribute(Qt.WA_NoSystemBackground)

        self.setFont(ResourcesCache.get("BigFont"))

        self._registeredTools = {}
        self._registeredInks = {}

        self._toolSlots = []
        self._inkSlots = []

        self._currentActiveToolSlot = None
        self._previousActiveToolSlot = None

        self._currentEditedInkSlot = None
        self._previousEditedInkSlot = None

        self._editMode = False

        self._backgroundColor = QColor(40, 40, 40)
        self._toolLabelColor = QColor(112, 231, 255)

        self._layout = QVBoxLayout()
        self._layout.setAlignment(Qt.AlignTop)
        self._layout.setContentsMargins(4, 4, 4, 4)

        top_layout = QHBoxLayout()

        self._layout.addLayout(top_layout)

        self._toolsLayout = QHBoxLayout()
        self._inksLayout = QHBoxLayout()

        self._toolsLayout.setContentsMargins(0, 0, 0, 0)
        self._toolsLayout.setAlignment(Qt.AlignLeft)

        self._inksLayout.setContentsMargins(0, 0, 0, 0)
        self._inksLayout.setAlignment(Qt.AlignRight)

        top_layout.addLayout(self._toolsLayout)
        top_layout.addLayout(self._inksLayout)

        self._toolsButtonGroup = QButtonGroup()
        self._toolsButtonGroup.buttonClicked.connect(
            self._on_tool_slot_triggered)

        self._inksButtonGroup = QButtonGroup()
        self._inksButtonGroup.setExclusive(False)
        self._inksButtonGroup.buttonClicked.connect(
            self._on_ink_slot_triggered)

        self.setLayout(self._layout)

        self._toolbarSubPanel = None
        self._toolsListWidget = None
        self._toolsOptionsPanel = None

        self._init_edit_panel()

        self._add_ink_slot(0)
        self._add_ink_slot(1)

        self.resize(0, 50)

    # -------------------------------------------------------------------------

    def get_tool_by_name(self, name):

        return self._registeredTools[name]

    def register_tool(self, tool, is_default=None):

        if tool.name not in self._registeredTools:

            self._registeredTools[tool.name] = tool
            self._toolsListWidget.addItem(tool.name)

            if is_default is True:
                self._toolsListWidget.setCurrentRow(0)

            self._build_tool_options_pane(tool)

            if len(self._toolSlots) < 4:
                slot_index = self._add_tool_slot(is_default)
                self._assign_tool_to_slot(tool, slot_index)

    def register_ink(self, ink, slot):

        if not ink.name in self._registeredInks:
            self._registeredInks[ink.name] = ink

            self._inksListWidget.addItem(ink.name)

            self._build_ink_options_pane(ink)

            if self._inkSlots[slot]['id'] is None:
                self._assign_ink_to_slot(ink, slot)

    def switch_tool_slot(self, slot):

        self._previousActiveToolSlot = self._currentActiveToolSlot

        self._currentActiveToolSlot = slot

        if self._currentActiveToolSlot == self._previousActiveToolSlot:
            return

        tool_name = self._toolSlots[slot]['id']

        self._toolSlots[slot]['button'].setChecked(True)

        self.toolChanged.emit(tool_name)

        self._select_tool_on_list(tool_name)

    # -------------------------------------------------------------------------

    def _go_back_to_last_tool(self):
        self.switch_tool_slot(self._previousActiveToolSlot)

    def _add_tool_slot(self, selected=None):

        slot_button = QPushButton()
        slot_button.setCheckable(True)

        index = len(self._toolSlots)

        if selected is not None and selected is True:
            slot_button.setChecked(True)

        slot = {'id': None, 'button': slot_button}

        if selected:
            self._currentActiveToolSlot = index

        self._toolSlots.append(slot)

        self._toolsButtonGroup.addButton(slot_button, index)

        self._toolsLayout.addWidget(slot_button)

        return index

    def _add_ink_slot(self, slot_number):

        slot_button = QPushButton()
        slot_button.setFont(self.font())
        slot_button.setStyleSheet(
            "border-color: rgb(56,56,56); background-color: rgb(17,17,"
            "17); font-size: 12pt;")

        index = len(self._inkSlots)

        if slot_number == 0:

            icon = QIcon()
            icon.addPixmap(QPixmap(":/icons/ico_mouse_button1"), QIcon.Normal,
                           QIcon.Off)

            slot_button.setIcon(icon)
            slot_button.setIconSize(QSize(18, 23))

        elif slot_number == 1:

            icon = QIcon()
            icon.addPixmap(QPixmap(":/icons/ico_mouse_button2"), QIcon.Normal,
                           QIcon.Off)

            slot_button.setIcon(icon)
            slot_button.setIconSize(QSize(18, 23))

        slot = {'id': None, 'button': slot_button}

        self._inkSlots.append(slot)

        self._inksButtonGroup.addButton(slot_button)

        self._inksButtonGroup.setId(slot_button, index)

        self._inksLayout.addWidget(slot_button)

        return index

    def _assign_tool_to_slot(self, tool, slot):

        if slot < 0 or slot > len(self._toolSlots) - 1:
            raise Exception(
                '[ToolBar] > _assignToolToSlot : invalid slot parameter')

        self._toolSlots[slot]['id'] = tool.name

        icon = tool.icon

        if icon is not None:
            tool_button = self._toolSlots[slot]['button']
            tool_button.setIcon(tool.icon)
            tool_button.setIconSize(QSize(24, 24))

    def _assign_ink_to_slot(self, ink, slot):

        if slot != 0 and slot != 1:
            raise Exception(
                '[ToolBar] > _assignInkToSlot : invalid slot parameter')

        ink_name = ink.name

        self._inkSlots[slot]['id'] = ink_name
        self._inkSlots[slot]['button'].setText(ink_name)

        if slot == 0:
            self.primaryInkChanged.emit(ink_name)
        elif slot == 1:
            self.secondaryInkChanged.emit(ink_name)

    def _init_edit_panel(self):

        self._toolbarSubPanel = QStackedWidget()

        # 1. Initialize Tools Control Panel -----------------------------------

        self._toolsListWidget = QListWidget()

        self._toolsListWidget.currentRowChanged.connect(
            lambda v: self._toolsOptionsPanel.setCurrentIndex(v))

        self._toolsListWidget.setMaximumSize(QSize(150, 200))

        self._toolsListWidget.itemClicked.connect(
            self._on_tool_list_item_clicked)

        # Tools Subpanel ------------------------------------------------------

        tools_control_panel = QWidget()

        tools_control_panel_layout = QHBoxLayout()

        tools_control_panel.setLayout(tools_control_panel_layout)

        tools_control_panel_layout.setAlignment(Qt.AlignLeft)

        # Tools List ----------------------------------------------------------

        tools_list_sublayout = QVBoxLayout()

        tools_list_sublayout.setAlignment(Qt.AlignTop)

        tools_list_sublayout.setContentsMargins(0, 0, 0, 0)

        tools_list_sublayout.addWidget(QLabel("Tools"))

        tools_list_sublayout.addWidget(self._toolsListWidget)

        tools_control_panel_layout.addLayout(tools_list_sublayout)

        # Tools Options -------------------------------------------------------

        tools_options_sublayout = QVBoxLayout()

        tools_options_sublayout.setAlignment(Qt.AlignTop)

        tools_control_panel_layout.addLayout(tools_options_sublayout)

        self._toolsOptionsPanel = QStackedWidget()

        tools_options_sublayout.addWidget(QLabel("Tools Options"))

        tools_options_sublayout.addWidget(self._toolsOptionsPanel)

        self._toolbarSubPanel.addWidget(tools_control_panel)

        # 2. Initialize Inks Control Panel ------------------------------------

        self._inksListWidget = QListWidget()

        self._inksListWidget.currentRowChanged.connect(
            lambda v: self._inksOptionsPanel.setCurrentIndex(v))

        self._inksListWidget.setMaximumSize(QSize(150, 200))

        self._inksListWidget.itemClicked.connect(
            self._on_ink_list_item_clicked)

        # Inks Subpanel -------------------------------------------------------

        inks_control_panel = QWidget()

        inks_control_panel_layout = QHBoxLayout()

        inks_control_panel.setLayout(inks_control_panel_layout)

        inks_control_panel_layout.setAlignment(Qt.AlignLeft)

        # Inks List -----------------------------------------------------------

        inks_list_sublayout = QVBoxLayout()

        inks_list_sublayout.setAlignment(Qt.AlignTop)

        inks_list_sublayout.setContentsMargins(0, 0, 0, 0)

        inks_list_sublayout.addWidget(QLabel("Inks"))

        inks_list_sublayout.addWidget(self._inksListWidget)

        inks_control_panel_layout.addLayout(inks_list_sublayout)

        # Inks Options --------------------------------------------------------

        inks_options_sublayout = QVBoxLayout()

        inks_options_sublayout.setAlignment(Qt.AlignTop)

        inks_control_panel_layout.addLayout(inks_options_sublayout)

        self._inksOptionsPanel = QStackedWidget()

        inks_options_sublayout.addWidget(QLabel("Ink Options"))

        inks_options_sublayout.addWidget(self._inksOptionsPanel)

        self._toolbarSubPanel.addWidget(inks_control_panel)

        # ---------------------------------------------------------------------

        self._layout.addWidget(self._toolbarSubPanel)

        self._toolbarSubPanel.setVisible(False)

    def _build_tool_options_pane(self, tool):

        pane = QWidget()

        pane_layout = QVBoxLayout()
        pane_layout.setAlignment(Qt.AlignTop)
        pane.setLayout(pane_layout)

        for prop in tool.properties.values():
            field_layout = QHBoxLayout()

            field_layout.addWidget(QLabel(prop.description))

            prop_widget = prop.build_property_widget()

            field_layout.addWidget(prop_widget)

            pane_layout.addLayout(field_layout)

        self._toolsOptionsPanel.addWidget(pane)

    def _build_ink_options_pane(self, ink):

        pane = QWidget()

        pane_layout = QVBoxLayout()
        pane_layout.setAlignment(Qt.AlignTop)
        pane.setLayout(pane_layout)

        for prop in ink.properties.values():
            field_layout = QHBoxLayout()
            field_layout.addWidget(QLabel(prop.description))

            prop_widget = prop.build_property_widget()

            field_layout.addWidget(prop_widget)

            pane_layout.addLayout(field_layout)

        self._inksOptionsPanel.addWidget(pane)

    def _select_tool_on_list(self, tool_name):

        tool_list_item = \
            self._toolsListWidget.findItems(tool_name, Qt.MatchExactly)[0]

        if tool_list_item is not None:
            self._toolsListWidget.setCurrentItem(tool_list_item)

    def _select_ink_on_list(self, ink_name):

        ink_list_item = \
            self._inksListWidget.findItems(ink_name, Qt.MatchExactly)[0]

        if ink_list_item is not None:
            self._inksListWidget.setCurrentItem(ink_list_item)

    def _toggle_edit_mode(self):

        if not self._editMode:

            self._show_sub_panel()

        else:

            self._hide_sub_panel()

        self.update()

    def _show_sub_panel(self):

        self._editMode = True
        self.resize(self.width(), 300)
        self._toolbarSubPanel.setVisible(True)

    def _hide_sub_panel(self):

        self._editMode = False
        self.resize(self.width(), 50)
        self._toolbarSubPanel.setVisible(False)

        self._finish_ink_edit_mode()

    def _finish_ink_edit_mode(self):

        if self._currentEditedInkSlot is not None:
            self._inksButtonGroup.button(self._currentEditedInkSlot). \
                setStyleSheet("border-color: rgb(56,56,56);")
            self._currentEditedInkSlot = None
            self._previousEditedInkSlot = None
            self._inksListWidget.setCurrentRow(0)
            self._toolbarSubPanel.setCurrentIndex(0)

    # -------------------------------------------------------------------------

    def mousePressEvent(self, e):

        self._toggle_edit_mode()

        e.accept()

    def wheelEvent(self, e):

        e.accept()

    def enterEvent(self, e):

        self.mouseEntered.emit()
        self.setCursor(Qt.PointingHandCursor)

    def leaveEvent(self, e):

        self.mouseLeft.emit()

    def _on_tool_slot_triggered(self):

        self._toolbarSubPanel.setCurrentIndex(0)

        triggered_slot = self._toolsButtonGroup.checkedId()

        if self._currentEditedInkSlot is not None:
            self._finish_ink_edit_mode()

        self.switch_tool_slot(triggered_slot)

        self.update()

    def _on_ink_slot_triggered(self, slot_button):

        if not self._editMode:
            self._show_sub_panel()

        triggered_slot_id = self._inksButtonGroup.id(slot_button)

        if triggered_slot_id != self._currentEditedInkSlot:

            self._previousEditedInkSlot = self._currentEditedInkSlot

            self._currentEditedInkSlot = triggered_slot_id

            if self._previousEditedInkSlot is not None:
                self._inksButtonGroup. \
                    button(self._previousEditedInkSlot). \
                    setStyleSheet("border-color: rgb(56,56,56);")

            slot_button.setStyleSheet("border-color: rgb(255,0,0);")

            self._toolbarSubPanel.setCurrentIndex(1)

            ink_name = self._inkSlots[triggered_slot_id]['id']

            self._select_ink_on_list(ink_name)

            if triggered_slot_id == 0:
                self.primaryInkChanged.emit(ink_name)
            elif triggered_slot_id == 1:
                self.secondaryInkChanged.emit(ink_name)

        else:

            self._hide_sub_panel()

    def _on_tool_list_item_clicked(self, new_item):

        new_item_name = new_item.text()
        self._assign_tool_to_slot(self.get_tool_by_name(new_item_name),
                                  self._currentActiveToolSlot)
        self.toolChanged.emit(new_item_name)
        self._toolbarSubPanel.update()

    def _on_ink_list_item_clicked(self, item):

        item_name = item.text()

        ink = self._registeredInks[item_name]

        if ink is not None:
            self._assign_ink_to_slot(ink, self._currentEditedInkSlot)
Beispiel #27
0
class TimekeeperUi(QtWidgets.QMainWindow):
    """User interface for the timekeeper"""
    def __init__(self):
        super().__init__()
        uic.loadUi('src/UI/timekeeper.ui', self)

        self.pause_button = self.findChild(QtWidgets.QPushButton, 'pause_button')
        self.pause_button.clicked.connect(timekeeper.pause_time)

        self.start_button = self.findChild(QtWidgets.QPushButton, 'start_button')
        self.start_button.clicked.connect(timekeeper.resume_time)

        signals.timer_expired.connect(self.update_time)

        self.update_time(timekeeper.current_day,
                         timekeeper.current_time_hour,
                         timekeeper.current_time_min,
                         timekeeper.current_time_sec)

        self.button_group = QButtonGroup()
        self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'one_times_button'))
        self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'two_times_button'))
        self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'five_times_button'))
        self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'ten_times_button'))
        self.button_group.addButton(self.findChild(QtWidgets.QPushButton, 'fifty_times_button'))
        self.button_group.addButton(self.findChild(QtWidgets.QPushButton,
                                                   'one_hundred_times_button'))

        # Set the correct button according to the time factor
        self.button_group.button(PERIODS.index(timekeeper.time_factor)*-1 - 2) \
                                 .setChecked(True)

        self.button_group.buttonClicked.connect(self.update_speed)

        self.show()

    def update_time(self, day, hours, mins, secs):
        """Updates the time label

        :param int day: Current day
        :param int hours: Current hours
        :param int mins: Current minutes
        :param int secs: Current seconds

        """
        days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

        period = 'am'
        if hours in range(12, 24):
            period = 'pm'

        if hours == 0:
        	hours = 12
        elif hours > 12:
            hours -= 12

        time_text = "{} {:02}:{:02}:{:02} {}".format(days[day], hours, mins, secs, period)

        time_label = self.findChild(QtWidgets.QLabel, 'time_label')
        time_label.setText(time_text)

    def update_speed(self):
        """Method called when a new speed factor is selected

        Note: Button ids start at -2 and go down for some god awful reason
        """
        # We don't need the lock here because this variable is only being used for the sleep time
        timekeeper.time_factor = PERIODS[abs(self.button_group.checkedId()) - 2]
Beispiel #28
0
class SettingsDialog(QDialog, Ui_Dialog):
    def __init__(self, parent):
        super().__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.setupUi(self)

        self.lineEdit_loginUsername.setText(app.settings.get("account", "username"))
        self.lineEdit_loginPassword.setText(app.settings.get("account", "password"))
        self.checkBox_autoLogin.setChecked(app.settings.getbool("account", "autologin"))
        self.checkBox_autoStartFrontend.setChecked(self.doesAutoStartFileExists())

        self.checkBox_enableDevelopersTools.setChecked(
            app.settings.getbool("frontend", "enabledeveloperstools"))
        self.checkBox_allowFlash.setChecked(app.settings.getbool("frontend", "allowflash"))
        self.checkBox_minimizeToSystray.setChecked(
            app.settings.getbool("frontend", "minimizetosystray"))
        self.checkBox_closeToMinimize.setChecked(
            app.settings.getbool("frontend", "closetominimize"))
        self.checkBox_popNotifications.setChecked(
            app.settings.getbool("frontend", "popnotifications"))
        self.checkBox_notifyBySound.setChecked(
            app.settings.getbool("frontend", "notifybysound"))
        self.checkBox_showMonitorWindow.setChecked(
            app.settings.getbool("frontend", "showmonitorwindow"))
        self.spinBox_monitorFullSpeed.setValue(
            app.settings.getint("frontend", "monitorfullspeed"))
        # clipboard related
        self.checkBox_watchClipboard.stateChanged.connect(self.slotWatchClipboardToggled)
        self.checkBox_watchClipboard.setChecked(app.settings.getbool("frontend", "watchclipboard"))
        self.slotWatchClipboardToggled(self.checkBox_watchClipboard.checkState())
        self.plaintext_watchPattern.setPlainText(app.settings.get("frontend", "watchpattern"))

        self.btngrp_etmStartWhen = QButtonGroup()
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen1, 1)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen2, 2)
        self.btngrp_etmStartWhen.addButton(self.radio_backendStartWhen3, 3)

        try:
            startEtmWhen = callXwaredInterface("getStartEtmWhen")
            self.btngrp_etmStartWhen.button(startEtmWhen).setChecked(True)
        except SocketDoesntExist:
            self.group_etmStartWhen.setEnabled(False)

        self.btn_addMount.clicked.connect(self.slotAddMount)
        self.btn_removeMount.clicked.connect(self.slotRemoveMount)
        self.btn_refreshMount.clicked.connect(self.setupMounts)

        # Mounts
        self.setupMounts()

        # backend setting is a different thing!
        self.setupETM()

    @staticmethod
    def doesAutoStartFileExists():
        return os.path.lexists(constants.FRONTEND_AUTOSTART_FILE)

    @pyqtSlot(int)
    def slotWatchClipboardToggled(self, state):
        # disable pattern settings, before
        # 1. complete patterns
        # 2. test glib key file compatibility
        self.plaintext_watchPattern.setReadOnly(True)
        self.plaintext_watchPattern.setEnabled(state)

    @pyqtSlot()
    def setupMounts(self):
        self.table_mounts.setRowCount(0)
        self.table_mounts.clearContents()

        permissionCheckResult = app.mountsFaker.permissionCheck()
        permissionCheckFailed = ["无法获得检测权限。运行{}查看原因。".format(constants.PERMISSIONCHECK)]

        mountsMapping = app.mountsFaker.getMountsMapping()
        for i, mount in enumerate(app.mountsFaker.mounts):
            # mounts = ['/path/to/1', 'path/to/2', ...]
            self.table_mounts.insertRow(i)
            self.table_mounts.setItem(i, 0, QTableWidgetItem(mount))
            # drive1: the drive letter it should map to, by alphabetical order
            drive1 = chr(ord('C') + i) + ":"
            self.table_mounts.setItem(i, 1, QTableWidgetItem(drive1))
            # drive2: the drive letter it actually is assigned to
            drive2 = mountsMapping.get(mount, "无")

            # check 1: permission
            errors = permissionCheckResult.get(mount, permissionCheckFailed)

            # check 2: mapping
            if drive1 != drive2:
                errors.append(
                    "警告:盘符映射在'{actual}',而不是'{should}'。需要重启后端修复。".format(
                        actual = drive2,
                        should = drive1))

            brush = QBrush()
            if errors:
                brush.setColor(Qt.red)
                errString = "\n".join(errors)
            else:
                brush.setColor(Qt.darkGreen)
                errString = "正常"
            errWidget = QTableWidgetItem(errString)
            errWidget.setForeground(brush)

            self.table_mounts.setItem(i, 2, errWidget)
            del brush, errWidget

        self.table_mounts.resizeColumnsToContents()

    @pyqtSlot()
    def slotAddMount(self):
        fileDialog = QFileDialog(self, Qt.Dialog)
        fileDialog.setFileMode(QFileDialog.Directory)
        fileDialog.setOption(QFileDialog.ShowDirsOnly, True)
        fileDialog.setViewMode(QFileDialog.List)
        fileDialog.setDirectory(os.environ["HOME"])
        if fileDialog.exec():
            selected = fileDialog.selectedFiles()[0]
            if selected in self.newMounts:
                return
            row = self.table_mounts.rowCount()
            self.table_mounts.insertRow(row)
            self.table_mounts.setItem(row, 0, QTableWidgetItem(selected))
            self.table_mounts.setItem(row, 1, QTableWidgetItem("新近添加"))
            self.table_mounts.setItem(row, 2, QTableWidgetItem("新近添加"))

    @pyqtSlot()
    def slotRemoveMount(self):
        row = self.table_mounts.currentRow()
        self.table_mounts.removeRow(row)

    @pyqtSlot()
    def accept(self):
        app.settings.set("account", "username", self.lineEdit_loginUsername.text())
        app.settings.set("account", "password", self.lineEdit_loginPassword.text())
        app.settings.setbool("account", "autologin", self.checkBox_autoLogin.isChecked())
        doesAutoStartFileExists = self.doesAutoStartFileExists()
        if self.checkBox_autoStartFrontend.isChecked() and not doesAutoStartFileExists:
            # mkdir if autostart dir doesn't exist
            try:
                os.mkdir(os.path.dirname(constants.FRONTEND_AUTOSTART_FILE))
            except OSError:
                pass  # already exists
            os.symlink(constants.DESKTOP_FILE_LOCATION,
                       constants.FRONTEND_AUTOSTART_FILE)
        elif (not self.checkBox_autoStartFrontend.isChecked()) and doesAutoStartFileExists:
            os.remove(constants.FRONTEND_AUTOSTART_FILE)

        app.settings.setbool("frontend", "enabledeveloperstools",
                             self.checkBox_enableDevelopersTools.isChecked())
        app.settings.setbool("frontend", "allowflash",
                             self.checkBox_allowFlash.isChecked())
        app.settings.setbool("frontend", "minimizetosystray",
                             self.checkBox_minimizeToSystray.isChecked())

        # A possible Qt bug
        # https://bugreports.qt-project.org/browse/QTBUG-37695
        app.settings.setbool("frontend", "closetominimize",
                             self.checkBox_closeToMinimize.isChecked())
        app.settings.setbool("frontend", "popnotifications",
                             self.checkBox_popNotifications.isChecked())
        app.settings.setbool("frontend", "notifybysound",
                             self.checkBox_notifyBySound.isChecked())

        app.settings.setbool("frontend", "showmonitorwindow",
                             self.checkBox_showMonitorWindow.isChecked())
        app.settings.setint("frontend", "monitorfullspeed",
                            self.spinBox_monitorFullSpeed.value())
        app.settings.setbool("frontend", "watchclipboard",
                             self.checkBox_watchClipboard.isChecked())
        # app.settings.set("frontend", "watchpattern",
        #                         self.plaintext_watchPattern.toPlainText())

        if self.group_etmStartWhen.isEnabled():
            startEtmWhen = self.btngrp_etmStartWhen.id(self.btngrp_etmStartWhen.checkedButton())
            try:
                callXwaredInterface("setStartEtmWhen", startEtmWhen)
            except SocketDoesntExist:
                QMessageBox.warning(None, "Xware Desktop",
                                    "选项未能成功设置:{}。".format(self.group_etmStartWhen.title()),
                                    QMessageBox.Ok, QMessageBox.Ok)

        app.settings.save()

        app.mountsFaker.mounts = self.newMounts
        app.settings.applySettings.emit()
        super().accept()

    @property
    def newMounts(self):
        return list(map(lambda row: self.table_mounts.item(row, 0).text(),
                        range(self.table_mounts.rowCount())))

    @pyqtSlot()
    def setupETM(self):
        # fill values
        lcPort = app.xwaredpy.lcPort
        self.lineEdit_lcport.setText(str(lcPort) if lcPort else "不可用")

        etmSettings = app.etmpy.getSettings()
        if etmSettings:
            self.spinBox_dSpeedLimit.setValue(etmSettings.dLimit)
            self.spinBox_uSpeedLimit.setValue(etmSettings.uLimit)
            self.spinBox_maxRunningTasksNum.setValue(etmSettings.maxRunningTasksNum)

            # connect signals
            self.accepted.connect(self.saveETM)
        else:
            self.spinBox_dSpeedLimit.setEnabled(False)
            self.spinBox_uSpeedLimit.setEnabled(False)
            self.spinBox_maxRunningTasksNum.setEnabled(False)

    @pyqtSlot()
    def saveETM(self):
        newsettings = EtmSetting(dLimit = self.spinBox_dSpeedLimit.value(),
                                 uLimit = self.spinBox_uSpeedLimit.value(),
                                 maxRunningTasksNum = self.spinBox_maxRunningTasksNum.value())

        app.etmpy.saveSettings(newsettings)
class MyWindow(QWidget):
    def __init__(self):
        super(MyWindow, self).__init__()
        self.initGUI("PyQt5 学习 ButtonGroup")

        # 设定窗口的布局管理器为 QGridLayout
        layout = QGridLayout()
        self.setLayout(layout)

        self.buttonGroup = QButtonGroup()
        # # 按钮不是互斥的,即可以同时选中多个按钮
        # self.buttonGroup.setExclusive(False)
        # 按钮是互斥的,即同一时刻只能选中1个按钮
        self.buttonGroup.setExclusive(True)
        # NOTE: 绑定信号与槽函数,信号是 buttonGroup.buttonClicked(id),槽函数是 on_button_clicked(id)
        self.buttonGroup.buttonClicked[int].connect(self.on_button_clicked)

        button = QPushButton("PushButton 1")
        self.buttonGroup.addButton(button, 1)
        layout.addWidget(button, 0, 0)

        button = QPushButton("PushButton 2")
        self.buttonGroup.addButton(button, 2)
        layout.addWidget(button, 0, 1)

        rdBtn = QRadioButton("单选按钮1")
        self.buttonGroup.addButton(rdBtn, 3)
        layout.addWidget(rdBtn, 1, 0)

        rdBtn = QRadioButton("单选按钮2")
        self.buttonGroup.addButton(rdBtn, 4)
        layout.addWidget(rdBtn, 1, 1)

        # 添加了复选框到同一个分组,四个按钮同时只能选择一个。
        checkbox = QCheckBox("复选框1")
        self.buttonGroup.addButton(checkbox, 5)
        layout.addWidget(checkbox, 2, 0)

        checkbox = QCheckBox("复选框2")
        self.buttonGroup.addButton(checkbox, 6)
        layout.addWidget(checkbox, 2, 1)

        # layout.setVerticalSpacing(5)
        # layout.setHorizontalSpacing(5)

        boxlayout = QBoxLayout(QBoxLayout.LeftToRight)
        label = QLabel("------分割线------")
        boxlayout.addWidget(label, 1, Qt.AlignHCenter)
        layout.addLayout(boxlayout, 3, 0, 1, 2, Qt.AlignJustify)

        layout2 = QGridLayout()
        layout.addLayout(layout2, 4, 0, 1, 2, Qt.AlignJustify)
        self.btn_group2 = QButtonGroup()
        self.btn_group2.setExclusive(False)
        self.btn_group2.buttonClicked[int].connect(self.on_btn_group2_clicked)

        radio = QRadioButton("神仙?")
        self.btn_group2.addButton(radio, 1)
        layout2.addWidget(radio, 0, 0, 2, 2, Qt.AlignJustify)

        layout2.setHorizontalSpacing(10)

        radio = QRadioButton("妖怪?")
        self.btn_group2.addButton(radio, 2)
        layout2.addWidget(radio, 0, 2, 2, 2, Qt.AlignJustify)

    def on_button_clicked(self, id):
        """
        遍历按钮组,找到这个按钮
        """
        for button in self.buttonGroup.buttons():
            if button is self.buttonGroup.button(id):
                print("%s was clicked" % (button.text()))

    def on_btn_group2_clicked(self, id):
        """
        第二个按钮分组有按钮被单击
        """
        for button in self.btn_group2.buttons():
            if button is self.btn_group2.button(id):
                print("%s was clicked" % (button.text()))

    def initGUI(self, title):
        """
        设置窗口大小和位置,以及标题
        """
        startx = 800
        starty = 400
        width = 480
        height = 320
        self.setGeometry(startx, starty, width, height)
        self.setWindowTitle(title)
Beispiel #30
0
class SummaryTab(QWidget):
    def __init__(self, leak, updateFlagIcon, notifyUnsavedChanges):
        super(SummaryTab, self).__init__()
        assert isinstance(leak, Leak)
        assert isinstance(leak.meta, LeakMetaInfo)
        self.leak = leak
        self.user_comment = QTextEdit("")
        self.leak_details = QLabel(str(self.leak.status))
        self.updateFlagIcon = updateFlagIcon
        self.notifyUnsavedChanges = notifyUnsavedChanges
        self.setupUI()

    def setupUI(self):

        summary_layout = QGridLayout()
        self.user_comment.textChanged.connect(self.commentChanged)
        comment = self.leak.meta.comment
        if comment == "":
            self.user_comment.setPlaceholderText("User comments")
        else:
            self.user_comment.setText(comment)

        # # # # #
        flags_group_box = QGroupBox("Rating")
        #icon_size = QSize(20, 20)
        font_size = QFontMetrics(self.user_comment.currentFont()).size(0,"A").height()
        font_size *= 1.1
        icon_size = QSize(font_size, font_size)
        
        flag_0 = createIconButton(icon_size, LeakFlags.NOLEAK)
        flag_1 = createIconButton(icon_size, LeakFlags.INVESTIGATE)
        flag_2 = createIconButton(icon_size, LeakFlags.LEAK)
        flag_3 = createIconButton(icon_size, LeakFlags.DONTCARE)

        flag_0.setCheckable(True)
        flag_1.setCheckable(True)
        flag_2.setCheckable(True)
        flag_3.setCheckable(True)
        self.flags_button_group = QButtonGroup()
        self.flags_button_group.buttonClicked[int].connect(self.bgClicked)
        self.flags_button_group.setExclusive(True)
        self.flags_button_group.addButton(flag_0, 0)
        self.flags_button_group.addButton(flag_1, 1)
        self.flags_button_group.addButton(flag_2, 2)
        self.flags_button_group.addButton(flag_3, 3)

        btn_id = flag_to_btn[self.leak.meta.flag]
        self.flags_button_group.button(btn_id).setChecked(True)
        # # # # #
        flags_hbox = QHBoxLayout()
        flags_hbox.addWidget(flag_0)
        flags_hbox.addWidget(flag_1)
        flags_hbox.addWidget(flag_2)
        flags_hbox.addWidget(flag_3)
        flags_group_box.setLayout(flags_hbox)
        flags_group_box.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        #
        statistic_group_box = QGroupBox("Statistics")
        statistic_grid = QGridLayout()

        rowid = 0
        if self.leak.status is not None:
            if self.leak.status.nsperformed:
                # Only show the highest value for generic leaks
                l = max(self.leak.status.nsleak, key=lambda l: l.normalized())
                lbl_circle = QLabel()
                lbl_circle.setPixmap(getCircle(getColor(l.normalized(), l.threshold())))
                lbl_circle.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
                lbl_text = QLabel("%s: %0.1f%%" % ("generic", l.normalized() * 100.0))
                statistic_grid.addWidget(lbl_circle, rowid, 0)
                statistic_grid.addWidget(lbl_text, rowid, 1)
                rowid += 1
            if len(self.leak.status.spperformed) > 0:
                # Filter leaks: only keep the highest value
                spleaks = dict()
                for l in self.leak.status.spleak:
                    key = (l.target, l.property)
                    if key in spleaks and spleaks[key].normalized() >= l.normalized():
                        continue
                    spleaks[key] = l

                for key, l in sorted(spleaks.items()):
                    lbl_circle = QLabel()
                    lbl_circle.setPixmap(getCircle(getColor(l.normalized(), l.threshold())))
                    lbl_circle.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
                    lbl_text = QLabel("%s[%s]: %0.1f%%" % (l.target, l.property, l.normalized() * 100.0))
                    statistic_grid.addWidget(lbl_circle, rowid, 0)
                    statistic_grid.addWidget(lbl_text, rowid, 1)
                    rowid += 1
        statistic_group_box.setLayout(statistic_grid)
        statistic_group_box.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.leak_details.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)

        summary_layout.addWidget(flags_group_box, 0, 0)
        if rowid > 0:
            summary_layout.addWidget(statistic_group_box, 1, 0)
        summary_layout.addWidget(self.leak_details, 2, 0)
        summary_layout.addWidget(self.user_comment, 0, 1, 3, 1)

        self.setLayout(summary_layout)

    def bgClicked(self, btn_id):
        debug(5, "[bgClicked] flag_%d clicked", btn_id)
        flag_id = btn_to_flag[btn_id]
        self.leak.meta.flag = flag_id
        self.updateFlagIcon(self.leak.ip, flag_id)
        self.notifyUnsavedChanges()

    def commentChanged(self):
        comment = self.user_comment.toPlainText()
        debug(5, "[usrComment]: %s", comment)
        self.leak.meta.comment = comment
        self.notifyUnsavedChanges()
Beispiel #31
0
class AltBaseDialog(QWidget):
    """Displays edit boxes for other number bases.
    """
    baseCode = {'X': 16, 'O': 8, 'B': 2, 'D': 10}

    def __init__(self, dlgRef, parent=None):
        QWidget.__init__(self, parent)
        self.dlgRef = dlgRef
        self.prevBase = None  # revert to prevBase after temp base change
        self.setAttribute(Qt.WA_QuitOnClose, False)
        self.setWindowTitle('rpCalc Alternate Bases')
        if self.dlgRef.calc.option.boolData('KeepOnTop'):
            self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
        else:
            self.setWindowFlags(Qt.Window)
        topLay = QVBoxLayout(self)
        self.setLayout(topLay)
        mainLay = QGridLayout()
        topLay.addLayout(mainLay)
        self.buttons = QButtonGroup(self)
        self.baseBoxes = {}
        hexButton = QPushButton('He&x')
        self.buttons.addButton(hexButton, 16)
        mainLay.addWidget(hexButton, 0, 0, Qt.AlignRight)
        self.baseBoxes[16] = AltBaseBox(16, self.dlgRef.calc)
        mainLay.addWidget(self.baseBoxes[16], 0, 1)
        octalButton = QPushButton('&Octal')
        self.buttons.addButton(octalButton, 8)
        mainLay.addWidget(octalButton, 1, 0, Qt.AlignRight)
        self.baseBoxes[8] = AltBaseBox(8, self.dlgRef.calc)
        mainLay.addWidget(self.baseBoxes[8], 1, 1)
        binaryButton = QPushButton('&Binary')
        self.buttons.addButton(binaryButton, 2)
        mainLay.addWidget(binaryButton, 2, 0, Qt.AlignRight)
        self.baseBoxes[2] = AltBaseBox(2, self.dlgRef.calc)
        mainLay.addWidget(self.baseBoxes[2], 2, 1)
        decimalButton = QPushButton('&Decimal')
        self.buttons.addButton(decimalButton, 10)
        mainLay.addWidget(decimalButton, 3, 0, Qt.AlignRight)
        self.baseBoxes[10] = AltBaseBox(10, self.dlgRef.calc)
        mainLay.addWidget(self.baseBoxes[10], 3, 1)
        for button in self.buttons.buttons():
            button.setCheckable(True)
        self.buttons.buttonClicked[int].connect(self.changeBase)
        self.bitsLabel = QLabel()
        self.bitsLabel.setAlignment(Qt.AlignHCenter)
        self.bitsLabel.setFrameStyle(QFrame.Box | QFrame.Plain)
        topLay.addSpacing(3)
        topLay.addWidget(self.bitsLabel)
        topLay.addSpacing(3)
        buttonLay = QHBoxLayout()
        topLay.addLayout(buttonLay)
        copyButton = QPushButton('Copy &Value')
        buttonLay.addWidget(copyButton)
        copyButton.clicked.connect(self.copyValue)
        closeButton = QPushButton('&Close')
        buttonLay.addWidget(closeButton)
        closeButton.clicked.connect(self.close)
        self.changeBase(self.dlgRef.calc.base, False)
        self.updateOptions()
        option = self.dlgRef.calc.option
        self.move(option.intData('AltBaseXPos', 0, 10000),
                  option.intData('AltBaseYPos', 0, 10000))

    def updateData(self):
        """Update edit box contents for current registers.
        """
        if self.prevBase and self.dlgRef.calc.flag != calccore.Mode.entryMode:
            self.changeBase(self.prevBase, False)
            self.prevBase = None
        for box in self.baseBoxes.values():
            box.setValue(self.dlgRef.calc.stack[0])

    def changeBase(self, base, endEntryMode=True):
        """Change core's base, button depression and label highlighting.
        """
        self.baseBoxes[self.dlgRef.calc.base].setHighlight(False)
        self.baseBoxes[base].setHighlight(True)
        self.buttons.button(base).setChecked(True)
        if endEntryMode and self.dlgRef.calc.base != base and \
                self.dlgRef.calc.flag == calccore.Mode.entryMode:
            self.dlgRef.calc.flag = calccore.Mode.saveMode
        self.dlgRef.calc.base = base

    def setCodedBase(self, baseCode, temp=True):
        """Set new base from letter code, temporarily if temp is true.
        """
        if temp:
            self.prevBase = self.dlgRef.calc.base
        else:
            self.prevBase = None
        try:
            self.changeBase(AltBaseDialog.baseCode[baseCode], not temp)
        except KeyError:
            pass

    def updateOptions(self):
        """Update bit limit and two's complement use.
        """
        self.dlgRef.calc.setAltBaseOptions()
        if self.dlgRef.calc.useTwosComplement:
            text = '{0} bit, two\'s complement'.format(
                self.dlgRef.calc.numBits)
        else:
            text = '{0} bit, no two\'s complement'.format(
                self.dlgRef.calc.numBits)
        self.bitsLabel.setText(text)

    def copyValue(self):
        """Copy the value in the current base to the clipboard.
        """
        text = str(self.baseBoxes[self.dlgRef.calc.base].text())
        clip = QApplication.clipboard()
        if clip.supportsSelection():
            clip.setText(text, QClipboard.Selection)
        clip.setText(text)

    def keyPressEvent(self, keyEvent):
        """Pass all keypresses to main dialog.
        """
        self.dlgRef.keyPressEvent(keyEvent)

    def keyReleaseEvent(self, keyEvent):
        """Pass all key releases to main dialog.
        """
        self.dlgRef.keyReleaseEvent(keyEvent)

    def closeEvent(self, closeEvent):
        """Change back to base 10 before closing.
        """
        self.changeBase(10)
        QWidget.closeEvent(self, closeEvent)
Beispiel #32
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.create_main_window_actions([
            QActionProperties(
                name=main_window_constants.EXPORT_ACTION_NAME,
                icon=QIcon(':/icons/export'),
                text='&Export',
                shortcut='Ctrl+E',
                status_tip='Export to Python code',
                triggered=self.export_diagram,
            ),
            QActionProperties(
                name=main_window_constants.DELETE_ACTON_NAME,
                icon=QIcon(':/icons/delete'),
                text='&Delete',
                shortcut='Delete',
                status_tip='Delete item from diagram',
                triggered=self.delete_item,
            ),
            QActionProperties(
                name=main_window_constants.TO_FRONT_ACTION_NAME,
                icon=QIcon(':/icons/bring_to_front'),
                text='Bring to &Front',
                shortcut='Ctrl+F',
                status_tip='Bring item to front',
                triggered=self.bring_to_front,
            ),
            QActionProperties(
                name=main_window_constants.TO_BACK_ACTION_NAME,
                icon=QIcon(':/icons/send_to_back'),
                text='Send to &Back',
                shortcut='Ctrl+B',
                status_tip='Send item to back',
                triggered=self.send_to_back,
            ),
        ])

        self.create_file_menu()
        self.create_edit_menu()
        self.create_frameworks_toolbar()
        self.create_edit_diagram_toolbar()
        self.create_pointer_toolbar()
        self.create_diagram_scene_and_view()
        self.create_framework_toolbox()

        self.layout = QHBoxLayout()
        self.layout.addWidget(self.framework_toolbox)
        self.layout.addWidget(self.view)

        self.widget = QWidget()
        self.widget.setLayout(self.layout)

        self.setWindowTitle(main_window_constants.MAIN_WINDOW_TITLE)
        self.setCentralWidget(self.widget)

    # Create methods.
    def create_main_window_actions(
            self, main_window_actions: List[QActionProperties]):
        self.main_window_actions = dict()
        for main_window_action in main_window_actions:
            self.main_window_actions[main_window_action.name] = QAction(
                main_window_action.icon,
                main_window_action.text,
                self,
                shortcut=main_window_action.shortcut,
                statusTip=main_window_action.status_tip,
                triggered=main_window_action.triggered,
            )

    def create_file_menu(self):
        self.file_menu = self.menuBar().addMenu(
            main_window_constants.FILE_MENU_NAME)
        self.file_menu.addAction(
            self.main_window_actions[main_window_constants.EXPORT_ACTION_NAME])

    def create_edit_menu(self):
        self.edit_menu = self.menuBar().addMenu(
            main_window_constants.EDIT_MENU_NAME)
        self.edit_menu.addAction(
            self.main_window_actions[main_window_constants.DELETE_ACTON_NAME])
        self.edit_menu.addSeparator()
        self.edit_menu.addAction(self.main_window_actions[
            main_window_constants.TO_FRONT_ACTION_NAME])
        self.edit_menu.addAction(self.main_window_actions[
            main_window_constants.TO_BACK_ACTION_NAME])

    def create_frameworks_toolbar(self):
        self.frameworks_label = QLabel(main_window_constants.FRAMEWORKS_LABEL)

        self.frameworks_combobox = QComboBox()
        self.frameworks_combobox.setEditable(False)
        for framework in frameworks_utils.get_sorted_frameworks_list():
            self.frameworks_combobox.addItem(framework)

        self.frameworks_toolbar = self.addToolBar(
            main_window_constants.FRAMEWORKS_TOOLBAR_NAME)
        self.frameworks_toolbar.addWidget(self.frameworks_label)
        self.frameworks_toolbar.addWidget(self.frameworks_combobox)

    def create_edit_diagram_toolbar(self):
        self.edit_diagram_toolbar = self.addToolBar(
            main_window_constants.DIAGRAM_EDIT_TOOLBAR_NAME)
        self.edit_diagram_toolbar.addAction(
            self.main_window_actions[main_window_constants.DELETE_ACTON_NAME])
        self.edit_diagram_toolbar.addAction(self.main_window_actions[
            main_window_constants.TO_FRONT_ACTION_NAME])
        self.edit_diagram_toolbar.addAction(self.main_window_actions[
            main_window_constants.TO_BACK_ACTION_NAME])

    def create_pointer_toolbar(self):
        pointer_button = QToolButton()
        pointer_button.setCheckable(True)
        pointer_button.setChecked(True)
        pointer_button.setIcon(QIcon(':/icons/pointer'))

        line_pointer_button = QToolButton()
        line_pointer_button.setCheckable(True)
        line_pointer_button.setIcon(QIcon(':/icons/line_pointer'))

        self.pointer_type_group = QButtonGroup()
        self.pointer_type_group.addButton(pointer_button,
                                          DiagramScene.move_item)
        self.pointer_type_group.addButton(line_pointer_button,
                                          DiagramScene.insert_line)
        self.pointer_type_group.buttonClicked[int].connect(
            self.pointer_group_clicked)

        scene_scale_combo = QComboBox()
        scene_scale_combo.addItems(main_window_constants.DIAGRAM_SCENE_SCALES)
        scene_scale_combo.setCurrentIndex(
            main_window_constants.DIAGRAM_SCENE_SCALES.index(
                main_window_constants.DIAGRAM_SCENE_DEFAULT_SCALE))
        scene_scale_combo.currentIndexChanged[str].connect(
            self.scene_scale_changed)

        self.pointer_toolbar = self.addToolBar(
            main_window_constants.POINTER_TYPE_TOOLBAR_NAME)
        self.pointer_toolbar.addWidget(pointer_button)
        self.pointer_toolbar.addWidget(line_pointer_button)
        self.pointer_toolbar.addWidget(scene_scale_combo)

    def create_diagram_scene_and_view(self):
        self.scene = DiagramScene(self.edit_menu)
        self.scene.setSceneRect(
            QRectF(0, 0, main_window_constants.DIAGRAM_SCENE_SIZE,
                   main_window_constants.DIAGRAM_SCENE_SIZE))
        self.scene.item_inserted.connect(self.item_inserted)
        self.view = QGraphicsView(self.scene)

    def create_framework_toolbox(self):
        framework_layers = frameworks_utils.get_framework_layers(
            self.get_selected_framework())

        self.framework_layers_button_group = QButtonGroup()
        self.framework_layers_button_group.setExclusive(False)
        self.framework_layers_button_group.buttonClicked[int].connect(
            self.framework_layers_button_group_clicked)

        layout = QGridLayout()
        for framework_layer in framework_layers:
            layout.addWidget(
                self.create_framework_layer_widget(framework_layer()))

        layout.setRowStretch(3, 10)
        layout.setColumnStretch(2, 10)

        item_widget = QWidget()
        item_widget.setLayout(layout)

        self.framework_toolbox = QToolBox()
        self.framework_toolbox.setSizePolicy(
            QSizePolicy(
                QSizePolicy.Maximum,
                QSizePolicy.Ignored,
            ), )
        self.framework_toolbox.setMinimumWidth(item_widget.sizeHint().width())
        self.framework_toolbox.addItem(item_widget,
                                       main_window_constants.LAYERS)

    # Callback methods.
    def export_diagram(self):
        nodes = self.get_nodes_from_scene()

        if len(nodes) == 0:
            return

        edges = self.get_edges_from_scene()
        nodes_mapping = self.create_nodes_mapping(nodes)
        uni_graph = graph_utils.create_graph_from_qt_elements(
            nodes, edges, nodes_mapping)
        bi_graph = graph_utils.create_graph_from_qt_elements(
            nodes, edges, nodes_mapping, is_bi_directional=True)

        is_one_connected_component = graph_utils.is_one_connected_component(
            bi_graph)
        graph_topological_sort = graph_utils.create_graph_topological_sort(
            uni_graph)
        root_nodes = graph_utils.get_root_nodes(uni_graph)
        is_all_root_nodes_are_input_layers = graph_utils.is_all_root_nodes_are_input_layers(
            nodes, root_nodes)

        if not is_one_connected_component:
            self.show_model_graph_eval_error_msg(
                main_window_constants.MODEL_GRAPH_MULTIPLE_COMPONENTS_ERROR_MSG
            )
        elif graph_topological_sort is None:
            self.show_model_graph_eval_error_msg(
                main_window_constants.MODEL_GRAPH_CYCLE_ERROR_MSG)
        elif not is_all_root_nodes_are_input_layers:
            self.show_model_graph_eval_error_msg(
                main_window_constants.
                MODEL_GRAPH_ROOT_NODE_IS_NOT_INPUT_ERROR_MSG)
        else:
            input_definitions = self.build_input_definitions(
                map(nodes.__getitem__, root_nodes))
            layer_definitions = self.build_layer_definitions(
                nodes, graph_topological_sort, root_nodes)
            model_connections = self.build_model_connections(
                nodes, uni_graph, graph_topological_sort, root_nodes)
            framework_template = frameworks_utils.get_formatted_framework_template(
                self.get_selected_framework(),
                input_definitions,
                layer_definitions,
                model_connections,
            )

            file_path, _ = QFileDialog.getSaveFileName(
                self,
                'Export Model As',
                'talzeeq.py',
                'Python Language (*.py);;'
                'All files (*.*)',
            )

            if file_path:
                with open(file_path, 'w') as fp:
                    fp.write(framework_template)

    def delete_item(self):
        for item in self.scene.selectedItems():
            if isinstance(item, DiagramItem):
                item.remove_arrows()
            self.scene.removeItem(item)

    def bring_to_front(self):
        for selected_item in self.scene.selectedItems():
            z_value = 0
            for item in selected_item.collidingItems():
                if item.zValue() >= z_value and isinstance(item, DiagramItem):
                    z_value = item.zValue() + 0.1
            selected_item.setZValue(z_value)

    def send_to_back(self):
        for selected_item in self.scene.selectedItems():
            z_value = 0
            for item in selected_item.collidingItems():
                if item.zValue() <= z_value and isinstance(item, DiagramItem):
                    z_value = item.zValue() - 0.1
            selected_item.setZValue(z_value)

    def pointer_group_clicked(self, index: int):
        self.scene.set_mode(self.pointer_type_group.checkedId())

    def scene_scale_changed(self, scale: str):
        new_scale = int(
            scale[:scale.index(main_window_constants.
                               DIAGRAM_SCENE_SCALE_PERCENT)]) / 100.0
        old_transform = self.view.transform()
        self.view.resetTransform()
        self.view.translate(old_transform.dx(), old_transform.dy())
        self.view.scale(new_scale, new_scale)

    def item_inserted(self, item: DiagramItem):
        self.pointer_type_group.button(DiagramScene.move_item).setChecked(True)
        self.scene.set_mode(self.pointer_type_group.checkedId())
        layer_index = frameworks_utils.get_framework_layer_index(
            self.get_selected_framework(),
            item.framework_layer.__class__,
        )
        self.framework_layers_button_group.button(layer_index).setChecked(
            False)

    def framework_layers_button_group_clicked(self, id: int):
        buttons = self.framework_layers_button_group.buttons()

        for button in buttons:
            if self.framework_layers_button_group.button(id) != button:
                button.setChecked(False)

        if self.framework_layers_button_group.button(id).isChecked():
            self.scene.set_item_type(id)
            self.scene.set_framework_name(self.get_selected_framework())
            self.scene.set_mode(DiagramScene.insert_item)
        else:
            self.scene.set_mode(DiagramScene.move_item)

    # Helper methods.
    def get_selected_framework(self) -> str:
        return str(self.frameworks_combobox.currentText())

    def get_nodes_from_scene(self) -> List[DiagramItem]:
        return list(
            filter(lambda item: isinstance(item, DiagramItem),
                   self.scene.items()))

    def get_edges_from_scene(self) -> List[Arrow]:
        return list(
            filter(lambda item: isinstance(item, Arrow), self.scene.items()))

    def create_nodes_mapping(
            self, nodes: List[DiagramItem]) -> Dict[DiagramItem, int]:
        return {node: index for index, node in enumerate(nodes)}

    def show_model_graph_eval_error_msg(self, message: str):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Critical)
        msg.setText(main_window_constants.MODEL_GRAPH_EVAL_ERROR_MSG_TEXT)
        msg.setInformativeText(message)
        msg.setWindowTitle(
            main_window_constants.MODEL_GRAPH_EVAL_ERROR_MSG_TEXT)
        msg.exec_()

    def build_input_definitions(self, root_nodes: List[DiagramItem]) -> str:
        input_definitions = list()
        for node in root_nodes:
            input_definitions.append(
                node.get_framework_layer().layer_definition())
        return ', '.join(input_definitions)

    def build_layer_definitions(
        self,
        nodes: List[DiagramItem],
        graph_topological_sort: List[int],
        root_nodes: List[int],
    ) -> str:
        layer_definitions = list()
        for element in graph_topological_sort:
            if element not in root_nodes:
                layer_definitions.append(
                    nodes[element].get_framework_layer().layer_definition())
        return '\n'.join(layer_definitions)

    def build_model_connections(
        self,
        nodes: List[DiagramItem],
        graph: List[List[int]],
        graph_topological_sort: List[int],
        root_nodes: List[int],
    ) -> str:
        model_connections = list()

        for element in graph_topological_sort:
            parents = list()
            is_root = list()
            for node in range(len(graph)):
                if element in graph[node]:
                    parents.append(nodes[node].get_framework_layer())
                    is_root.append(node in root_nodes)

            layer_connections = nodes[element].get_framework_layer(
            ).layer_connections(parents, is_root)
            if layer_connections:
                model_connections.append(layer_connections)

        return '\n'.join(model_connections)

    def create_framework_layer_widget(
            self, framework_layer: LayerInterface) -> QWidget:
        button = QToolButton()
        button.setText(framework_layer.layer_name())
        button.setCheckable(True)
        self.framework_layers_button_group.addButton(
            button,
            frameworks_utils.get_framework_layer_index(
                self.get_selected_framework(),
                framework_layer.__class__,
            ),
        )

        layout = QVBoxLayout()
        layout.addWidget(button)

        widget = QWidget()
        widget.setLayout(layout)

        return widget
Beispiel #33
0
class PochaPlayerInputWidget(QFrame):

    winnerSet = QtCore.pyqtSignal(str)
    newExpected = QtCore.pyqtSignal()
    handsClicked = QtCore.pyqtSignal(str, str)

    def __init__(self, player, engine, colour=None, parent=None):
        super(PochaPlayerInputWidget, self).__init__(parent)
        self.player = player
        self.engine = engine
        self.winner = False
        self.pcolour = colour
        self.mainLayout = QVBoxLayout(self)
        self.mainLayout.setSpacing(0)

        self.label = QLabel(self)
        self.label.setText(self.player)
        self.mainLayout.addWidget(self.label)
        self.label.setAutoFillBackground(False)
        self.setFrameShape(QFrame.Panel)
        self.setFrameShadow(QFrame.Raised)
        self.label.setScaledContents(True)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setWordWrap(False)
        css = ("QLabel {{ font-size: 24px; font-weight: bold; "
               "color:rgb({},{},{});}}")
        self.label.setStyleSheet(css.format(self.pcolour.red(),
                                            self.pcolour.green(),
                                            self.pcolour.blue()))

        self.expectedGroupBox = QFrame(self)
        self.mainLayout.addWidget(self.expectedGroupBox)
        self.ebLayout = QHBoxLayout(self.expectedGroupBox)
        self.ebLayout.setSpacing(0)
        self.ebLayout.setContentsMargins(2, 2, 2, 2)
        self.expectedGroup = QButtonGroup(self)
        self.expectedGroup.buttonReleased.connect(self.expectedClickedAction)
        self.expectedButtons = []

        self.wonGroupBox = QFrame(self)
        self.mainLayout.addWidget(self.wonGroupBox)
        self.wbLayout = QHBoxLayout(self.wonGroupBox)
        self.wbLayout.setSpacing(0)
        self.wbLayout.setContentsMargins(2, 2, 2, 2)
        self.wonGroup = QButtonGroup(self)
        self.wonGroup.buttonReleased.connect(self.wonClickedAction)
        self.wonButtons = []
        for i in range(-1, 9):
            button = PochaHandsButton(str(i), self)
            self.expectedGroup.addButton(button, i)
            self.expectedButtons.append(button)
            button.toggled.connect(self.enableWonGroup)
            if i < 0:
                button.hide()
            else:
                self.ebLayout.addWidget(button)

            button = PochaHandsButton(str(i), self)
            self.wonGroup.addButton(button, i)
            self.wonButtons.append(button)
            if i < 0:
                button.hide()
            else:
                self.wbLayout.addWidget(button)

        self.reset()

    def reset(self):
        self.expectedButtons[0].setChecked(True)
        self.wonButtons[0].setChecked(True)
        self.refreshButtons()
        self.disableWonRow()

    def refreshButtons(self, forbidden=-1):
        hands = self.engine.getHands()
        for eb, wb in zip(self.expectedButtons, self.wonButtons):
            eb.setDisabled(int(eb.text()) > hands)
            if int(eb.text()) == forbidden:
                eb.setDisabled(True)
            wb.setDisabled(int(wb.text()) > hands)

    def disableWonRow(self, disable=True):
        if self.getExpectedHands() < 0:
            self.wonGroupBox.setDisabled(True)
        else:
            self.wonGroupBox.setDisabled(disable)

    def enableWonGroup(self, button):
        self.newExpected.emit()

    def isWinner(self): return False

    def getPlayer(self): return self.player

    def getScore(self):
        expected = self.expectedGroup.checkedId()
        won = self.wonGroup.checkedId()
        if expected < 0 or won < 0:
            return 0
        if expected == won:
            return 10 + 3 * won
        return -3 * abs(expected - won)

    def getWonHands(self): return self.wonGroup.checkedId()

    def getExpectedHands(self): return self.expectedGroup.checkedId()

    def setExpectedHands(self, number):
        if number < 0:
            self.expectedButtons[0].toggle()
            return True
        button = self.expectedGroup.button(number)
        if button.isEnabled():
            button.toggle()
            return True
        return False

    def setWonHands(self, number):
        if number < 0:
            self.wonButtons[0].toggle()
            return True
        button = self.wonGroup.button(number)
        if button.isEnabled():
            button.toggle()
            return True
        return False

    def expectedClickedAction(self, _):
        self.handsClicked.emit('expected', self.player)

    def wonClickedAction(self, _):
        self.handsClicked.emit('won', self.player)

    def setColour(self, colour):
        self.pcolour = colour
        css = ("QLabel {{ font-size: 24px; font-weight: bold; "
               "color:rgb({},{},{});}}")
        self.label.setStyleSheet(css.format(self.pcolour.red(),
                                            self.pcolour.green(),
                                            self.pcolour.blue()))
Beispiel #34
0
class ColormapDialog(QDialog):

    sigColormapChanged = pyqtSignal(object)

    def __init__(self, parent=None, name="Colormap Dialog"):
        QDialog.__init__(self, parent)
        self.setWindowTitle(name)
        self.title = name

        self.colormapList = [
            'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', 'YlOrBr',
            'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', 'GnBu', 'PuBu', 'YlGnBu',
            'PuBuGn', 'BuGn', 'YlGn'
        ]

        # histogramData is tupel(bins, counts)
        self.histogramData = None

        # default values
        self.dataMin = -10
        self.dataMax = 10
        self.minValue = 0
        self.maxValue = 1

        self.colormapIndex = 2
        self.colormapType = 0

        self.autoscale = False
        self.autoscale90 = False
        # main layout
        vlayout = QVBoxLayout(self)
        vlayout.setContentsMargins(10, 10, 10, 10)
        vlayout.setSpacing(0)

        # layout 1 : -combo to choose colormap
        #            -autoscale button
        #            -autoscale 90% button
        hbox1 = QWidget(self)
        hlayout1 = QHBoxLayout(hbox1)
        vlayout.addWidget(hbox1)
        hlayout1.setContentsMargins(0, 0, 0, 0)
        hlayout1.setSpacing(10)

        # combo
        self.combo = QComboBox(hbox1)
        for colormap in self.colormapList:
            self.combo.addItem(colormap)
        self.combo.activated[int].connect(self.colormapChange)
        hlayout1.addWidget(self.combo)

        # autoscale
        self.autoScaleButton = QPushButton("Autoscale", hbox1)
        self.autoScaleButton.setCheckable(True)
        self.autoScaleButton.setAutoDefault(False)
        self.autoScaleButton.toggled[bool].connect(self.autoscaleChange)
        hlayout1.addWidget(self.autoScaleButton)

        # autoscale 90%
        self.autoScale90Button = QPushButton("Autoscale 90%", hbox1)
        self.autoScale90Button.setCheckable(True)
        self.autoScale90Button.setAutoDefault(False)

        self.autoScale90Button.toggled[bool].connect(self.autoscale90Change)
        hlayout1.addWidget(self.autoScale90Button)

        # hlayout
        hbox0 = QWidget(self)
        self.__hbox0 = hbox0
        hlayout0 = QHBoxLayout(hbox0)
        hlayout0.setContentsMargins(0, 0, 0, 0)
        hlayout0.setSpacing(0)
        vlayout.addWidget(hbox0)
        #hlayout0.addStretch(10)

        self.buttonGroup = QButtonGroup()
        g1 = QCheckBox(hbox0)
        g1.setText("Linear")
        g2 = QCheckBox(hbox0)
        g2.setText("Logarithmic")
        g3 = QCheckBox(hbox0)
        g3.setText("Gamma")
        self.buttonGroup.addButton(g1, 0)
        self.buttonGroup.addButton(g2, 1)
        self.buttonGroup.addButton(g3, 2)
        self.buttonGroup.setExclusive(True)
        if self.colormapType == 1:
            self.buttonGroup.button(1).setChecked(True)
        elif self.colormapType == 2:
            self.buttonGroup.button(2).setChecked(True)
        else:
            self.buttonGroup.button(0).setChecked(True)
        hlayout0.addWidget(g1)
        hlayout0.addWidget(g2)
        hlayout0.addWidget(g3)
        vlayout.addWidget(hbox0)
        self.buttonGroup.buttonClicked[int].connect(self.buttonGroupChange)
        vlayout.addSpacing(20)

        hboxlimits = QWidget(self)
        hboxlimitslayout = QHBoxLayout(hboxlimits)
        hboxlimitslayout.setContentsMargins(0, 0, 0, 0)
        hboxlimitslayout.setSpacing(0)

        self.slider = None

        vlayout.addWidget(hboxlimits)

        vboxlimits = QWidget(hboxlimits)
        vboxlimitslayout = QVBoxLayout(vboxlimits)
        vboxlimitslayout.setContentsMargins(0, 0, 0, 0)
        vboxlimitslayout.setSpacing(0)
        hboxlimitslayout.addWidget(vboxlimits)

        # hlayout 2 : - min label
        #             - min texte
        hbox2 = QWidget(vboxlimits)
        self.__hbox2 = hbox2
        hlayout2 = QHBoxLayout(hbox2)
        hlayout2.setContentsMargins(0, 0, 0, 0)
        hlayout2.setSpacing(0)
        #vlayout.addWidget(hbox2)
        vboxlimitslayout.addWidget(hbox2)
        hlayout2.addStretch(10)

        self.minLabel = QLabel(hbox2)
        self.minLabel.setText("Minimum")
        hlayout2.addWidget(self.minLabel)

        hlayout2.addSpacing(5)
        hlayout2.addStretch(1)
        self.minText = MyQLineEdit(hbox2)
        self.minText.setFixedWidth(150)
        self.minText.setAlignment(QtCore.Qt.AlignRight)
        self.minText.returnPressed[()].connect(self.minTextChanged)
        hlayout2.addWidget(self.minText)

        # hlayout 3 : - min label
        #             - min text
        hbox3 = QWidget(vboxlimits)
        self.__hbox3 = hbox3
        hlayout3 = QHBoxLayout(hbox3)
        hlayout3.setContentsMargins(0, 0, 0, 0)
        hlayout3.setSpacing(0)
        #vlayout.addWidget(hbox3)
        vboxlimitslayout.addWidget(hbox3)

        hlayout3.addStretch(10)
        self.maxLabel = QLabel(hbox3)
        self.maxLabel.setText("Maximum")
        hlayout3.addWidget(self.maxLabel)

        hlayout3.addSpacing(5)
        hlayout3.addStretch(1)

        self.maxText = MyQLineEdit(hbox3)
        self.maxText.setFixedWidth(150)
        self.maxText.setAlignment(QtCore.Qt.AlignRight)

        self.maxText.returnPressed[()].connect(self.maxTextChanged)
        hlayout3.addWidget(self.maxText)

        # Graph widget for color curve...
        self.c = PlotWidget(self, backend=None)
        self.c.setGraphXLabel("Data Values")
        self.c.setInteractiveMode('select')

        self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0
        self.minmd = self.dataMin - self.marge
        self.maxpd = self.dataMax + self.marge

        self.c.setGraphXLimits(self.minmd, self.maxpd)
        self.c.setGraphYLimits(-11.5, 11.5)

        x = [self.minmd, self.dataMin, self.dataMax, self.maxpd]
        y = [-10, -10, 10, 10]
        self.c.addCurve(x,
                        y,
                        legend="ConstrainedCurve",
                        color='black',
                        symbol='o',
                        linestyle='-')
        self.markers = []
        self.__x = x
        self.__y = y
        labelList = ["", "Min", "Max", ""]
        for i in range(4):
            if i in [1, 2]:
                draggable = True
                color = "blue"
            else:
                draggable = False
                color = "black"
            #TODO symbol
            legend = "%d" % i
            self.c.addXMarker(x[i],
                              legend=legend,
                              text=labelList[i],
                              draggable=draggable,
                              color=color)
            self.markers.append((legend, ""))

        self.c.setMinimumSize(QSize(250, 200))
        vlayout.addWidget(self.c)

        self.c.sigPlotSignal.connect(self.chval)

        # colormap window can not be resized
        self.setFixedSize(vlayout.minimumSize())
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        vlayout.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

    def plotHistogram(self, data=None):
        if data is not None:
            self.histogramData = data
        if self.histogramData is None:
            return False
        bins, counts = self.histogramData
        self.c.addCurve(bins,
                        counts,
                        "Histogram",
                        color='darkYellow',
                        histogram='center',
                        yaxis='right',
                        fill=True)

    def _update(self):
        _logger.debug("colormap _update called")
        self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0
        self.minmd = self.dataMin - self.marge
        self.maxpd = self.dataMax + self.marge
        self.c.setGraphXLimits(self.minmd, self.maxpd)
        self.c.setGraphYLimits(-11.5, 11.5)

        self.__x = [self.minmd, self.dataMin, self.dataMax, self.maxpd]
        self.__y = [-10, -10, 10, 10]
        self.c.addCurve(self.__x,
                        self.__y,
                        legend="ConstrainedCurve",
                        color='black',
                        symbol='o',
                        linestyle='-')
        self.c.clearMarkers()
        for i in range(4):
            if i in [1, 2]:
                draggable = True
                color = "blue"
            else:
                draggable = False
                color = "black"
            key = self.markers[i][0]
            label = self.markers[i][1]
            self.c.addXMarker(self.__x[i],
                              legend=key,
                              text=label,
                              draggable=draggable,
                              color=color)
        self.sendColormap()

    def buttonGroupChange(self, val):
        _logger.debug("buttonGroup asking to update colormap")
        self.setColormapType(val, update=True)
        self._update()

    def setColormapType(self, val, update=False):
        self.colormapType = val
        if self.colormapType == 1:
            self.buttonGroup.button(1).setChecked(True)
        elif self.colormapType == 2:
            self.buttonGroup.button(2).setChecked(True)
        else:
            self.colormapType = 0
            self.buttonGroup.button(0).setChecked(True)
        if update:
            self._update()

    def chval(self, ddict):
        _logger.debug("Received %s", ddict)
        if ddict['event'] == 'markerMoving':
            diam = int(ddict['label'])
            x = ddict['x']
            if diam == 1:
                self.setDisplayedMinValue(x)
            elif diam == 2:
                self.setDisplayedMaxValue(x)
        elif ddict['event'] == 'markerMoved':
            diam = int(ddict['label'])
            x = ddict['x']
            if diam == 1:
                self.setMinValue(x)
            if diam == 2:
                self.setMaxValue(x)

    """
    Colormap
    """

    def setColormap(self, colormap):
        self.colormapIndex = colormap
        if QTVERSION < '4.0.0':
            self.combo.setCurrentItem(colormap)
        else:
            self.combo.setCurrentIndex(colormap)

    def colormapChange(self, colormap):
        self.colormapIndex = colormap
        self.sendColormap()

    # AUTOSCALE
    """
    Autoscale
    """

    def autoscaleChange(self, val):
        self.autoscale = val
        self.setAutoscale(val)
        self.sendColormap()

    def setAutoscale(self, val):
        _logger.debug("setAutoscale called %s", val)
        if val:
            self.autoScaleButton.setChecked(True)
            self.autoScale90Button.setChecked(False)
            #self.autoScale90Button.setDown(False)
            self.setMinValue(self.dataMin)
            self.setMaxValue(self.dataMax)
            self.maxText.setEnabled(0)
            self.minText.setEnabled(0)
            self.c.setEnabled(False)
            #self.c.disablemarkermode()
        else:
            self.autoScaleButton.setChecked(False)
            self.autoScale90Button.setChecked(False)
            self.minText.setEnabled(1)
            self.maxText.setEnabled(1)
            self.c.setEnabled(True)
            #self.c.enablemarkermode()

    """
    set rangeValues to dataMin ; dataMax-10%
    """

    def autoscale90Change(self, val):
        self.autoscale90 = val
        self.setAutoscale90(val)
        self.sendColormap()

    def setAutoscale90(self, val):
        if val:
            self.autoScaleButton.setChecked(False)
            self.setMinValue(self.dataMin)
            self.setMaxValue(self.dataMax - abs(self.dataMax / 10))
            self.minText.setEnabled(0)
            self.maxText.setEnabled(0)
            self.c.setEnabled(False)
        else:
            self.autoScale90Button.setChecked(False)
            self.minText.setEnabled(1)
            self.maxText.setEnabled(1)
            self.c.setEnabled(True)
            self.c.setFocus()

    # MINIMUM
    """
    change min value and update colormap
    """

    def setMinValue(self, val):
        v = float(str(val))
        self.minValue = v
        self.minText.setText("%g" % v)
        self.__x[1] = v
        key = self.markers[1][0]
        label = self.markers[1][1]
        self.c.addXMarker(v,
                          legend=key,
                          text=label,
                          color="blue",
                          draggable=True)
        self.c.addCurve(self.__x,
                        self.__y,
                        legend="ConstrainedCurve",
                        color='black',
                        symbol='o',
                        linestyle='-')
        self.sendColormap()

    """
    min value changed by text
    """

    def minTextChanged(self):
        text = str(self.minText.text())
        if not len(text):
            return
        val = float(text)
        self.setMinValue(val)
        if self.minText.hasFocus():
            self.c.setFocus()

    """
    change only the displayed min value
    """

    def setDisplayedMinValue(self, val):
        val = float(val)
        self.minValue = val
        self.minText.setText("%g" % val)
        self.__x[1] = val
        key = self.markers[1][0]
        label = self.markers[1][1]
        self.c.addXMarker(val,
                          legend=key,
                          text=label,
                          color="blue",
                          draggable=True)
        self.c.addCurve(self.__x,
                        self.__y,
                        legend="ConstrainedCurve",
                        color='black',
                        symbol='o',
                        linestyle='-')

    # MAXIMUM
    """
    change max value and update colormap
    """

    def setMaxValue(self, val):
        v = float(str(val))
        self.maxValue = v
        self.maxText.setText("%g" % v)
        self.__x[2] = v
        key = self.markers[2][0]
        label = self.markers[2][1]
        self.c.addXMarker(v,
                          legend=key,
                          text=label,
                          color="blue",
                          draggable=True)
        self.c.addCurve(self.__x,
                        self.__y,
                        legend="ConstrainedCurve",
                        color='black',
                        symbol='o',
                        linestyle='-')
        self.sendColormap()

    """
    max value changed by text
    """

    def maxTextChanged(self):
        text = str(self.maxText.text())
        if not len(text): return
        val = float(text)
        self.setMaxValue(val)
        if self.maxText.hasFocus():
            self.c.setFocus()

    """
    change only the displayed max value
    """

    def setDisplayedMaxValue(self, val):
        val = float(val)
        self.maxValue = val
        self.maxText.setText("%g" % val)
        self.__x[2] = val
        key = self.markers[2][0]
        label = self.markers[2][1]
        self.c.addXMarker(val,
                          legend=key,
                          text=label,
                          color="blue",
                          draggable=True)
        self.c.addCurve(self.__x,
                        self.__y,
                        legend="ConstrainedCurve",
                        color='black',
                        symbol='o',
                        linestyle='-')

    # DATA values
    """
    set min/max value of data source
    """

    def setDataMinMax(self, minVal, maxVal, update=True):
        if minVal is not None:
            vmin = float(str(minVal))
            self.dataMin = vmin
        if maxVal is not None:
            vmax = float(str(maxVal))
            self.dataMax = vmax

        if update:
            # are current values in the good range ?
            self._update()

    def getColormap(self):

        if self.minValue > self.maxValue:
            vmax = self.minValue
            vmin = self.maxValue
        else:
            vmax = self.maxValue
            vmin = self.minValue
        cmap = [
            self.colormapIndex, self.autoscale, vmin, vmax, self.dataMin,
            self.dataMax, self.colormapType
        ]
        return cmap if self.exec_() else None

    """
    send 'ColormapChanged' signal
    """

    def sendColormap(self):
        _logger.debug("sending colormap")
        try:
            cmap = self.getColormap()
            self.sigColormapChanged.emit(cmap)
        except:
            sys.excepthook(sys.exc_info()[0],
                           sys.exc_info()[1],
                           sys.exc_info()[2])

    def colormapListToDict(colormapList):
        """Convert colormap from this dialog to :class:`PlotBackend`.
        :param colormapList: Colormap as returned by :meth:`getColormap`.
        :type colormapList: list or tuple
        :return: Colormap as used in :class:`PlotBackend`.
        :rtype: dict
        """
        index, autoscale, vMin, vMax, dataMin, dataMax, cmapType = colormapList
        # Warning, gamma cmapType is not supported in plot backend
        # Here it is silently replaced by linear as the default colormap
        return {
            'name': _COLORMAP_NAMES[index],
            'autoscale': autoscale,
            'vmin': vMin,
            'vmax': vMax,
            'normalization': 'log' if cmapType == 1 else 'linear',
            'colors': 256
        }

    def getColormap_name(self):
        self.getColormap()
        return _COLORMAP_NAMES[self.colormapIndex]

    def getColor(self):
        return _COLOR_NAMES[self.colormapIndex]

    def colormapDictToList(colormapDict):
        """Convert colormap from :class:`PlotBackend` to this dialog.
        :param dict colormapDict: Colormap as used in :class:`PlotBackend`.
        :return: Colormap as returned by :meth:`getColormap`.
        :rtype: list
        """
        cmapIndex = _COLORMAP_NAMES.index(colormapDict['name'])
        cmapType = 1 if colormapDict['normalization'].startswith('log') else 0
        return [
            cmapIndex,
            colormapDict['autoscale'],
            colormapDict['vmin'],
            colormapDict['vmax'],
            0,  # dataMin is not defined in PlotBackend colormap
            0,  # dataMax is not defined in PlotBackend colormap
            cmapType
        ]
class MainWindow(QMainWindow):
    InsertTextButton = 10
    items = {-2: "source", -3: "channel", -4: "sink"}

    def __init__(self):
        import _diagramscene_rc

        super(MainWindow, self).__init__()

        self.config_manipulations = FlumeConfig(self)
        properties_generator.dump_props()

        self.create_actions()
        self.create_menus()
        self.create_tool_box()
        self.clicked_button_id = 0

        self.scene = DiagramScene(self.item_menu)
        self.scene.setSceneRect(QRectF(0, 0, 5000, 5000))

        self.scene.itemInserted.connect(self.item_inserted)
        self.scene.textInserted.connect(self.text_inserted)
        self.scene.itemSelected.connect(self.item_selected)

        self.create_tool_bars()
        # self.scene.enable_grid()

        layout = QHBoxLayout()
        layout.addWidget(self.tool_box)
        self.view = QGraphicsView(self.scene)
        self.view.centerOn(0, 0)
        layout.addWidget(self.view)

        self.widget = QWidget()
        self.widget.setLayout(layout)

        self.setCentralWidget(self.widget)
        self.setWindowTitle("The Flume Illustrator")

    # noinspection PyAttributeOutsideInit,PyArgumentList
    def create_actions(self):

        self.to_front_action = QAction(QIcon(':/images/bringtofront.png'),
                                       "Bring to &Front", self, shortcut="Ctrl+F",
                                       statusTip="Bring item to front", triggered=self.bring_to_front)
        self.send_back_action = QAction(QIcon(':/images/sendtoback.png'),
                                        "Send to &Back", self, shortcut="Ctrl+B",
                                        statusTip="Send item to back", triggered=self.send_to_back)
        self.bold_action = QAction(QIcon(':/images/bold.png'),
                                   "Bold", self, checkable=True, shortcut="Ctrl+B",
                                   triggered=self.handle_font_change)
        self.italic_action = QAction(QIcon(':/images/italic.png'),
                                     "Italic", self, checkable=True, shortcut="Ctrl+I",
                                     triggered=self.handle_font_change)
        self.underline_action = QAction(QIcon(':/images/underline.png'),
                                        "Underline", self, checkable=True, shortcut="Ctrl+U",
                                        triggered=self.handle_font_change)

        self.delete_action = QAction(QIcon(':/images/delete.png'),
                                     "Delete", self, shortcut="Delete", statusTip='Delete item from diagram',
                                     triggered=self.delete_item)
        self.exit_action = QAction("Exit", self, shortcut="Ctrl+X",
                                   statusTip="Quit program", triggered=self.close)
        self.about_action = QAction("About", self, shortcut="Ctrl+B",
                                    triggered=self.about)
        self.load_config_action = QAction("Load", self, shortcut="Ctrl+O",
                                          statusTip="Load config file", triggered=self.config_manipulations.load_config)

        self.enable_grid_action = QAction("Enable grid", self, checkable=True, triggered=self.enable_grid)

    # noinspection PyAttributeOutsideInit
    def create_menus(self):
        self.file_menu = self.menuBar().addMenu("File")
        self.file_menu.addAction(self.load_config_action)
        self.file_menu.addAction(self.exit_action)

        self.item_menu = self.menuBar().addMenu("Item")
        self.item_menu.addAction(self.delete_action)
        self.item_menu.addSeparator()
        self.item_menu.addAction(self.to_front_action)
        self.item_menu.addAction(self.send_back_action)

        self.about_menu = self.menuBar().addMenu("Help")
        self.about_menu.addAction(self.about_action)

    # noinspection PyAttributeOutsideInit,PyUnresolvedReferences
    def create_tool_box(self):
        self.button_group = QButtonGroup()
        self.button_group.setExclusive(False)
        self.button_group.buttonClicked[int].connect(self.button_group_clicked)

        layout = QGridLayout()
        layout.addWidget(self.create_cell_widget("Source", "source"), 0, 0)
        layout.addWidget(self.create_cell_widget("Channel", "channel"), 0, 1)
        layout.addWidget(self.create_cell_widget("Sink", "sink"), 1, 0)

        text_button = QToolButton()
        text_button.setCheckable(True)
        self.button_group.addButton(text_button, self.InsertTextButton)
        text_button.setIcon(QIcon(QPixmap(':/images/textpointer.png').scaled(30, 30)))
        text_button.setIconSize(QSize(50, 50))

        text_layout = QGridLayout()
        text_layout.addWidget(text_button, 0, 0, Qt.AlignHCenter)
        text_layout.addWidget(QLabel("Text"), 1, 0, Qt.AlignCenter)
        text_widget = QWidget()
        text_widget.setLayout(text_layout)
        layout.addWidget(text_widget, 1, 1)

        layout.setRowStretch(3, 10)
        layout.setColumnStretch(2, 10)

        item_widget = QWidget()
        item_widget.setLayout(layout)

        self.tool_box = QToolBox()
        self.tool_box.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored))
        self.tool_box.setMinimumWidth(item_widget.sizeHint().width())
        self.tool_box.addItem(item_widget, "Basic Flume Items")

    # noinspection PyAttributeOutsideInit,PyUnresolvedReferences
    def create_tool_bars(self):

        self.edit_tool_bar = self.addToolBar("Edit")
        self.edit_tool_bar.addAction(self.delete_action)
        self.edit_tool_bar.addAction(self.to_front_action)
        self.edit_tool_bar.addAction(self.send_back_action)

        self.edit_tool_bar.addAction(self.enable_grid_action)

        self.font_combo = QFontComboBox()
        self.font_combo.currentFontChanged.connect(self.current_font_changed)

        self.font_size_combo = QComboBox()
        self.font_size_combo.setEditable(True)
        for i in range(8, 30, 2):
            self.font_size_combo.addItem(str(i))
        validator = QIntValidator(2, 64, self)
        self.font_size_combo.setValidator(validator)
        self.font_size_combo.currentIndexChanged.connect(self.font_size_changed)

        self.font_color_tool_button = QToolButton()
        self.font_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.font_color_tool_button.setMenu(
            self.create_color_menu(self.text_color_changed, Qt.black))
        self.text_action = self.font_color_tool_button.menu().defaultAction()
        self.font_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/textpointer.png',
                                               Qt.black))
        self.font_color_tool_button.setAutoFillBackground(True)
        self.font_color_tool_button.clicked.connect(self.text_button_triggered)

        self.fill_color_tool_button = QToolButton()
        self.fill_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.fill_color_tool_button.setMenu(
            self.create_color_menu(self.item_color_changed, Qt.white))
        self.fillAction = self.fill_color_tool_button.menu().defaultAction()
        self.fill_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/floodfill.png',
                                               Qt.white))
        self.fill_color_tool_button.clicked.connect(self.fill_button_triggered)

        self.line_color_tool_button = QToolButton()
        self.line_color_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.line_color_tool_button.setMenu(
            self.create_color_menu(self.line_color_changed, Qt.black))
        self.lineAction = self.line_color_tool_button.menu().defaultAction()
        self.line_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/linecolor.png',
                                               Qt.black))
        self.line_color_tool_button.clicked.connect(self.line_button_triggered)

        self.text_tool_bar = self.addToolBar("Font")
        self.text_tool_bar.addWidget(self.font_combo)
        self.text_tool_bar.addWidget(self.font_size_combo)
        self.text_tool_bar.addAction(self.bold_action)
        self.text_tool_bar.addAction(self.italic_action)
        self.text_tool_bar.addAction(self.underline_action)

        self.color_tool_bar = self.addToolBar("Color")
        self.color_tool_bar.addWidget(self.font_color_tool_button)
        self.color_tool_bar.addWidget(self.fill_color_tool_button)
        self.color_tool_bar.addWidget(self.line_color_tool_button)

        self.loading_tool_bar = self.addToolBar("Load")
        self.loading_tool_bar.addAction(self.load_config_action)

        pointer_button = QToolButton()
        pointer_button.setCheckable(True)
        pointer_button.setChecked(True)
        pointer_button.setIcon(QIcon(":/images/pointer.png"))
        line_pointer_button = QToolButton()
        line_pointer_button.setCheckable(True)
        line_pointer_button.setIcon(QIcon(":/images/linepointer.png"))

        self.pointer_type_group = QButtonGroup()
        self.pointer_type_group.addButton(pointer_button, DiagramScene.MoveItem)
        self.pointer_type_group.addButton(line_pointer_button, DiagramScene.InsertLine)
        self.pointer_type_group.buttonClicked[int].connect(self.pointer_group_clicked)

        self.scene_scale_combo = QComboBox()
        self.scene_scale_combo.addItems(["50%", "75%", "100%", "125%", "150%"])
        self.scene_scale_combo.setCurrentIndex(2)
        self.scene_scale_combo.currentIndexChanged[str].connect(self.scene_scale_changed)

        self.pointer_tool_bar = self.addToolBar("Pointer type")
        self.pointer_tool_bar.addWidget(pointer_button)
        self.pointer_tool_bar.addWidget(line_pointer_button)
        self.pointer_tool_bar.addWidget(self.scene_scale_combo)

    def button_group_clicked(self, button_id):
        buttons = self.button_group.buttons()
        self.clicked_button_id = button_id
        for button in buttons:
            if self.button_group.button(button_id) != button:
                button.setChecked(False)
        if button_id == self.InsertTextButton:
            self.scene.set_mode(DiagramScene.InsertText)
        else:
            self.scene.set_item_type(self.items[button_id])
            self.scene.set_mode(DiagramScene.InsertItem)

    def delete_item(self):
        for item in self.scene.selectedItems():
            if isinstance(item, FlumeDiagramItem):
                item.remove_arrows()
            self.scene.removeItem(item)

    # noinspection PyTypeChecker,PyCallByClass
    def about(self):

        # noinspection PyArgumentList
        QMessageBox.about(self, "About Flume Illustrator", "The Flume illustrator shows config-file details")

    def pointer_group_clicked(self):
        self.scene.set_mode(self.pointer_type_group.checkedId())

    def bring_to_front(self):
        if not self.scene.selectedItems():
            return

        selected_item = self.scene.selectedItems()[0]
        overlap_items = selected_item.collidingItems()

        z_value = 0
        for item in overlap_items:
            if item.zValue() >= z_value and isinstance(item, FlumeDiagramItem):
                z_value = item.zValue() + 0.1
        selected_item.setZValue(z_value)

    def send_to_back(self):
        if not self.scene.selectedItems():
            return

        selected_item = self.scene.selectedItems()[0]
        overlap_items = selected_item.collidingItems()

        z_value = 0
        for item in overlap_items:
            if item.zValue() <= z_value and isinstance(item, FlumeDiagramItem):
                z_value = item.zValue() - 0.1
        selected_item.setZValue(z_value)

    def scene_scale_changed(self, scale):
        new_scale = float(scale[:scale.index("%")]) / 100
        old_transform = self.view.transform()
        self.view.resetTransform()
        self.view.translate(old_transform.dx(), old_transform.dy())
        self.view.scale(new_scale, new_scale)

    def item_inserted(self, diagram_type):
        self.pointer_type_group.button(DiagramScene.MoveItem).setChecked(True)
        self.scene.set_mode(self.scene.DefaultMode)
        self.button_group.button(self.clicked_button_id).setChecked(False)

    def text_inserted(self, item):
        self.button_group.button(self.InsertTextButton).setChecked(False)
        self.scene.set_mode(self.pointer_type_group.checkedId())

    def current_font_changed(self, font):
        self.handle_font_change()

    def font_size_changed(self, font=None):
        self.handle_font_change()

    def text_color_changed(self):
        self.text_action = self.sender()
        self.font_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/textpointer.png',
                                               QColor(self.text_action.data())))
        self.text_button_triggered()

    def item_color_changed(self):
        self.fillAction = self.sender()
        self.fill_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/floodfill.png',
                                               QColor(self.fillAction.data())))
        self.fill_button_triggered()

    def line_color_changed(self):
        self.lineAction = self.sender()
        self.line_color_tool_button.setIcon(
            self.create_color_tool_button_icon(':/images/linecolor.png',
                                               QColor(self.lineAction.data())))
        self.line_button_triggered()

    def text_button_triggered(self):
        self.scene.set_text_color(QColor(self.text_action.data()))

    def fill_button_triggered(self):
        self.scene.set_item_color(QColor(self.fillAction.data()))

    def line_button_triggered(self):
        self.scene.set_line_color(QColor(self.lineAction.data()))

    def handle_font_change(self):
        font = self.font_combo.currentFont()
        font.setPointSize(int(self.font_size_combo.currentText()))
        if self.bold_action.isChecked():
            font.setWeight(QFont.Bold)
        else:
            font.setWeight(QFont.Normal)
        font.setItalic(self.italic_action.isChecked())
        font.setUnderline(self.underline_action.isChecked())

        self.scene.setFont(font)

    def item_selected(self, item):
        font = item.font()
        self.font_combo.setCurrentFont(font)
        self.font_size_combo.setEditText(str(font.pointSize()))
        self.bold_action.setChecked(font.weight() == QFont.Bold)
        self.italic_action.setChecked(font.italic())
        self.underline_action.setChecked(font.underline())

    def create_cell_widget(self, text, diagram_type):
        item = FlumeObject(diagram_type, "")
        icon = QIcon(item.pictogram.image())

        button = QToolButton()
        button.setIcon(icon)
        button.setIconSize(QSize(50, 50))
        button.setCheckable(True)
        self.button_group.addButton(button)  # , diagram_type

        layout = QGridLayout()
        layout.addWidget(button, 0, 0, Qt.AlignHCenter)
        layout.addWidget(QLabel(text), 1, 0, Qt.AlignHCenter)

        widget = QWidget()
        widget.setLayout(layout)

        return widget

    # noinspection PyArgumentList
    def create_color_menu(self, slot, default_color):
        colors = [Qt.black, Qt.white, Qt.red, Qt.blue, Qt.yellow]
        names = ["black", "white", "red", "blue", "yellow"]

        color_menu = QMenu(self)
        for color, name in zip(colors, names):
            action = QAction(self.create_color_icon(color), name, self,
                             triggered=slot)
            action.setData(QColor(color))
            color_menu.addAction(action)
            if color == default_color:
                color_menu.setDefaultAction(action)
        return color_menu

    @staticmethod
    def create_color_tool_button_icon(image_file, color):
        pixmap = QPixmap(50, 80)
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        image = QPixmap(image_file)
        target = QRect(0, 0, 50, 60)
        source = QRect(0, 0, 42, 42)
        painter.fillRect(QRect(0, 60, 50, 80), color)
        painter.drawPixmap(target, image, source)
        painter.end()

        return QIcon(pixmap)

    @staticmethod
    def create_color_icon(color):
        pixmap = QPixmap(20, 20)
        painter = QPainter(pixmap)
        painter.setPen(Qt.NoPen)
        painter.fillRect(QRect(0, 0, 20, 20), color)
        painter.end()

        return QIcon(pixmap)

    def enable_grid(self):
        if self.enable_grid_action.isChecked():
            color = Qt.black
        else:
            color = Qt.white
        for i in range(50):
            for j in range(50):
                self.scene.addEllipse(i * 100, j * 100, 2, 2, QPen(color))