Beispiel #1
0
class FileChooser(QWidget):
    fileOpened = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.folderBox = QComboBox(self)
        self.explorerTree = FileTreeView(self)
        self.explorerTree.doubleClickCallback = self._fileOpened
        self.explorerModel = QFileSystemModel(self)
        self.explorerModel.setFilter(
            QDir.AllDirs | QDir.Files | QDir.NoDotAndDotDot)
        self.explorerModel.setNameFilters(["*.py"])
        self.explorerModel.setNameFilterDisables(False)
        self.explorerTree.setModel(self.explorerModel)
        for index in range(1, self.explorerModel.columnCount()):
            self.explorerTree.hideColumn(index)
        self.setCurrentFolder()
        self.folderBox.currentIndexChanged[int].connect(
            self.updateCurrentFolder)

        layout = QVBoxLayout(self)
        layout.addWidget(self.folderBox)
        layout.addWidget(self.explorerTree)
        layout.setContentsMargins(5, 5, 0, 0)

    def _fileOpened(self, modelIndex):
        path = self.explorerModel.filePath(modelIndex)
        if os.path.isfile(path):
            self.fileOpened.emit(path)

    def currentFolder(self):
        return self.explorerModel.rootPath()

    def setCurrentFolder(self, path=None):
        if path is None:
            app = QApplication.instance()
            path = app.getScriptsDirectory()
        else:
            assert os.path.isdir(path)
        self.explorerModel.setRootPath(path)
        self.explorerTree.setRootIndex(self.explorerModel.index(path))
        self.folderBox.blockSignals(True)
        self.folderBox.clear()
        style = self.style()
        dirIcon = style.standardIcon(style.SP_DirIcon)
        self.folderBox.addItem(dirIcon, os.path.basename(path))
        self.folderBox.insertSeparator(1)
        self.folderBox.addItem(self.tr("Browse…"))
        self.folderBox.setCurrentIndex(0)
        self.folderBox.blockSignals(False)

    def updateCurrentFolder(self, index):
        if index < self.folderBox.count() - 1:
            return
        path = QFileDialog.getExistingDirectory(
            self, self.tr("Choose Directory"), self.currentFolder(),
            QFileDialog.ShowDirsOnly)
        if path:
            QSettings().setValue("scripting/path", path)
            self.setCurrentFolder(path)
Beispiel #2
0
class tb_spectrum(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.layout = QVBoxLayout()
        label = QLabel(_("Solar spectrum") + ":")
        self.layout.addWidget(label)

        self.cb = QComboBox()
        self.cb.activated.connect(self.on_cb_model_changed)
        self.layout.addWidget(self.cb)
        self.update()
        self.setLayout(self.layout)
        self.show()

    def get_text(self):
        out = self.cb.currentText()
        out = out.split(" ")[0]
        return out

    def file_name_set_start(self, start):
        self.start = start

    def file_name_set_end(self, end):
        self.end = end

    def find_models(self):
        ret = []
        path = get_plugins_path()

        for file in glob.glob(os.path.join(path, "*")):
            file_name = os.path.basename(file)
            if file_name.startswith("light_"):
                if file_name.endswith(".dll") or file_name.endswith(".so"):
                    ret.append(
                        os.path.splitext(os.path.basename(file_name[6:]))[0])

        return ret

    def on_cb_model_changed(self):
        cb_text = self.cb.currentText()
        inp_update_token_value("light.inp", "#sun", cb_text)

    def update(self):
        self.cb.blockSignals(True)
        models = find_light_source()
        for i in range(0, len(models)):
            self.cb.addItem(models[i])

        used_model = inp_get_token_value("light.inp", "#sun")

        if models.count(used_model) == 0:
            used_model = "sun"
            inp_update_token_value("light.inp", "#sun", "sun")

        self.cb.setCurrentIndex(self.cb.findText(used_model))
        #scan_item_add("light.inp","#sun","Light source",1)
        self.cb.blockSignals(False)
Beispiel #3
0
class WosMoveActionWidget(QWidget):
    combo_updated = pyqtSignal()

    def __init__(self, index, parent=None):
        QWidget.__init__(self, parent)
        self.index = index

        self.layout = QGridLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)

        self.layout.addWidget(QLabel("Move %s:" % index, self), 0, 0)
        self.move_ship_combo = QComboBox(self)
        self.move_ship_combo.currentTextChanged.connect(self.combo_updated)
        self.layout.addWidget(self.move_ship_combo, 0, 1)
        self.move_action_combo = QComboBox(self)
        self.move_action_combo.currentTextChanged.connect(self.combo_updated)
        self.move_action_combo.addItem('Forward', cCommonGame.Action.FWD)
        self.move_action_combo.addItem('Turn clockwise', cCommonGame.Action.CW)
        self.move_action_combo.addItem('Turn anti-clockwise', cCommonGame.Action.CCW)
        self.move_action_combo.addItem('Skip', cCommonGame.Action.NOP)
        self.layout.addWidget(self.move_action_combo, 0, 2)

    def get_index(self):
        return self.index

    def get_move_info(self):
        return self.move_ship_combo.currentData(), self.move_action_combo.currentData()

    def set_ship_actions(self, ship_id, action):
        self.move_ship_combo.setCurrentText(str(ship_id))
        if action == cCommonGame.Action.FWD:
            self.move_action_combo.setCurrentText('Forward')
        elif action == cCommonGame.Action.CW:
            self.move_action_combo.setCurrentText('Turn clockwise')
        elif action == cCommonGame.Action.CCW:
            self.move_action_combo.setCurrentText('Turn anti-clockwise')
        else:
            self.move_action_combo.setCurrentText('Skip')

    def update_move_ship_combo(self, ships):
        self.move_ship_combo.blockSignals(True)
        # Preserve last command
        old_text = self.move_ship_combo.currentText()
        self.move_ship_combo.clear()
        for ship_id, ship in ships.items():
            if ship and not ship.ship_info.is_sunken and ship.type is ItemType.SHIP:
                self.move_ship_combo.addItem(str(ship_id), ship_id)
        if not old_text:
            # Default index
            self.move_ship_combo.setCurrentIndex(self.index - 1)
        else:
            self.move_ship_combo.setCurrentText(old_text)
        self.move_ship_combo.blockSignals(False)
Beispiel #4
0
 def setEditorData(self, editor: QtWidgets.QComboBox,
                   index: QtCore.QModelIndex):
     editor.blockSignals(True)
     dflist = index.internalPointer()  # type: DFItemList
     item = dflist[index.row()]  # type: DFItem
     column = index.column()
     if column == 1:
         editor.setCurrentIndex(editor.findText(str(item.x_accessor)))
     elif column == 2:
         editor.setCurrentIndex(editor.findText(str(item.y_accessor)))
     elif column == 3:
         editor.setCurrentIndex(editor.findText(str(item.z_accessor)))
     editor.blockSignals(False)
Beispiel #5
0
class SidePanel(QDockWidget):
    def __init__(self, title, scene=None, parent=None):
        super().__init__(title, parent)
        self.setWidget(QWidget())
        self.scene = None
        self.stepbox = QComboBox()
        self.steptext = QTextEdit()
        self.stepbox.currentTextChanged.connect(self.report)
        layout = QVBoxLayout(self.widget())
        layout.addSpacing(20)
        layout.addWidget(self.stepbox)
        layout.addSpacing(10)
        layout.addWidget(self.steptext)
        layout.addSpacing(20)

        self.connect_scene(scene)

    def connect_scene(self, scene):
        self.disconnect()
        self.scene = scene

        if scene == None:
            self.atoms = {0: ""}
            self._init_stepbox()
            self.set_to_step(0)

        else:
            self.atoms = scene._model.get_atoms()
            self._init_stepbox()
            self.set_to_step(scene._current_step)
            self.scene.currentStepChanged.connect(self.set_to_step)
            self.stepbox.currentTextChanged.connect(self.scene.go_to_step)

    def disconnect(self):
        if self.scene != None:
            self.scene.currentStepChanged.disconnect(self.set_to_step)
            self.stepbox.currentTextChanged.disconnect(self.scene.go_to_step)

    def report(self, step):
        print(f"Sending request to go to step {step}!")

    def set_to_step(self, step):
        if int(step) in self.atoms:
            self.stepbox.blockSignals(True)
            self.stepbox.setCurrentText(str(step))
            self.stepbox.blockSignals(False)
            self.steptext.setText(".\n".join(self.atoms[step]))

    def _init_stepbox(self):
        self.stepbox.blockSignals(True)
        self.stepbox.clear()
        if "0" not in self.atoms:
            self.stepbox.addItem("0")
        for step in sorted(self.atoms):
            self.stepbox.addItem(str(step))
        self.stepbox.blockSignals(False)
Beispiel #6
0
class Window(QDialog):
    def __init__(self):
        super().__init__()

        self.title = "PyQt5 Combo Box"
        self.top = 200
        self.left = 500
        self.width = 300
        self.height = 100

        self.InitWindow()

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

        vbox = QVBoxLayout()

        self.combo = QComboBox()
        self.combo.currentTextChanged.connect(self.comboChanged)
        self.combo.blockSignals(True)
        self.combo.clear()
        self.combo.addItem("Python")
        self.combo.addItem("Java")
        self.combo.addItem("C++")
        self.combo.addItem("C#")
        self.combo.addItem("Ruby")
        self.combo.blockSignals(False)

        self.combo.currentTextChanged.connect(self.comboChanged)

        self.label = QLabel()
        self.label.setFont(QtGui.QFont("Sanserif", 15))
        self.label.setStyleSheet('color:red')

        vbox.addWidget(self.combo)
        vbox.addWidget(self.label)

        self.setLayout(vbox)

        self.show()

    def comboChanged(self):
        text = self.combo.currentText()
        self.label.setText("You Have Selected : " + text)
Beispiel #7
0
def fill_combobox(combobox: QtWidgets.QComboBox,
                  values: Iterable[Any],
                  text_func: Callable = str,
                  block_signals=False):
    """Fills the combobox with given values. Stores the values as user data
    and displays the string representations as item labels. Previous items
    are removed from the combobox.

    Args:
        combobox: combobox to fill
        values: collection of values to be added to the combobox
        text_func: function that detenmines how values are presented in
            text form
        block_signals: whether signals from combobox are blocked during filling
    """
    if block_signals:
        combobox.blockSignals(True)
    combobox.clear()
    for value in values:
        combobox.addItem(text_func(value), userData=value)
    if block_signals:
        combobox.blockSignals(False)
class snapshot_slider(QWidget):

	changed = pyqtSignal()

	def cal_min_max(self):

		self.z_max=-1e40
		self.z_min=1e40

		for i in range(0,len(self.dirs)):
			fname=os.path.join(self.dirs[i],self.files_combo.currentText())
			x=[]
			y=[]
			z=[]

			my_data=dat_file()
			if dat_file_read(my_data,fname) == True:
				#print(z)
				temp_max,temp_min=dat_file_max_min(my_data)

				if temp_max>self.z_max:
					self.z_max=temp_max

				if temp_min<self.z_min:
					self.z_min=temp_min
		
	def update(self):
		self.dirs=[]
		if os.path.isdir(self.path)==True:
			for name in os.listdir(self.path):
				if name!="." and name!= "..":
					full_path=os.path.join(self.path, name)
					if os.path.isdir(full_path):
						self.dirs.append(full_path)
		self.slider_max=len(self.dirs)-1
		self.slider0.setMaximum(self.slider_max)
		self.update_file_combo()

	def slider0_change(self):
		value = self.slider0.value()
		self.label0.setText(str(value))
		self.changed.emit()

	def get_file_name(self):
		file_path=os.path.join(self.path,str(self.slider0.value()),self.files_combo.currentText())
		if os.path.isfile(file_path)==False:
			file_path=None
		return file_path

	def set_path(self,path):
		self.path=path
		self.update()
		self.cal_min_max()

		
	def __init__(self):
		QWidget.__init__(self)
		self.path=""
		
		self.setWindowTitle(_("Snapshot slider")) 
		
		self.main_vbox = QVBoxLayout()

		self.slider_hbox0= QHBoxLayout()
		self.slider_max=30
		
		self.slider0 = QSlider(Qt.Horizontal)
		self.slider0.setMinimum(10)
		self.slider0.setMaximum(self.slider_max)

		self.slider0.setTickPosition(QSlider.TicksBelow)
		self.slider0.setTickInterval(5)
		self.slider0.valueChanged.connect(self.slider0_change)
		self.slider0.setMinimumSize(300, 80)

		self.slider_hbox0.addWidget(self.slider0)

		self.label0 = QLabel()
		self.label0.setText("")

		self.slider0.setValue(20)

		self.slider_hbox0.addWidget(self.label0)

		self.widget0=QWidget()
		self.widget0.setLayout(self.slider_hbox0)

		self.main_vbox.addWidget(self.widget0)


################
		self.slider_hbox1= QHBoxLayout()
		self.label1 = QLabel()
		self.label1.setText("File")
		self.slider_hbox1.addWidget(self.label1)

		self.files_combo=QComboBox()
		self.slider_hbox1.addWidget(self.files_combo)

		self.files_combo.currentIndexChanged.connect(self.files_combo_changed)

		self.widget1=QWidget()
		self.widget1.setLayout(self.slider_hbox1)

		self.main_vbox.addWidget(self.widget1)

###############

		self.setLayout(self.main_vbox)

	def update_file_combo(self):
		self.files_combo.blockSignals(True)
		self.files_combo.clear()
		path=os.path.join(self.path,str(self.slider0.value()))
		if os.path.isdir(path)==True:
			for name in os.listdir(path):
				full_path=os.path.join(path, name)
				if os.path.isfile(full_path):
					if name!="snapshot_info.dat":
						self.files_combo.addItem(name)

		all_items  = [self.files_combo.itemText(i) for i in range(self.files_combo.count())]

		for i in range(0,len(all_items)):
			if all_items[i] == "Jn.dat":
				self.files_combo.setCurrentIndex(i)
		self.files_combo.blockSignals(False)

		
	def files_combo_changed(self):
		self.cal_min_max()
		self.changed.emit()
Beispiel #9
0
class LedgerAuthDialog(QDialog):
    def __init__(self, handler, keystore: Ledger_KeyStore, data: Dict[str, Any]):
        '''Ask user for 2nd factor authentication. Support text and security card methods.
        Use last method from settings, but support downgrade.
        '''
        QDialog.__init__(self, handler.top_level_window())
        self.handler = handler
        self.txdata = data
        self.idxs = self.txdata['keycardData'] if self.txdata['confirmationType'] > 1 else ''
        self.setMinimumWidth(600)
        self.setWindowTitle(_("Ledger Wallet Authentication"))
        self.cfg = copy.deepcopy(keystore.cfg)
        self.dongle = keystore.get_client().dongle
        self.pin = ''

        self.devmode = self.getDevice2FAMode()
        if self.devmode == 0x11 or self.txdata['confirmationType'] == 1:
            self.cfg['mode'] = 0

        vbox = QVBoxLayout()
        self.setLayout(vbox)

        def on_change_mode(idx):
            self.cfg['mode'] = 0 if self.devmode == 0x11 else idx if idx > 0 else 1
            if self.cfg['mode'] > 0:
                keystore.cfg = self.cfg
            self.update_dlg()
        def return_pin():
            self.pin = (self.pintxt.text() if self.txdata['confirmationType'] == 1
                        else self.cardtxt.text())
            self.pin.setText('')
            self.cardtxt.setText('')
            if self.cfg['mode'] == 1:
                self.pin = ''.join(chr(int(str(i),16)) for i in self.pin)
            self.accept()

        self.modebox = QWidget()
        modelayout = QHBoxLayout()
        self.modebox.setLayout(modelayout)
        modelayout.addWidget(QLabel(_("Method:")))
        self.modes = QComboBox()
        modelayout.addWidget(self.modes, 2)
        modelayout.addStretch(1)
        self.modebox.setMaximumHeight(50)
        vbox.addWidget(self.modebox)

        self.populate_modes()
        self.modes.currentIndexChanged.connect(on_change_mode)

        self.helpmsg = QTextEdit()
        self.helpmsg.setStyleSheet("QTextEdit { background-color: lightgray; }")
        self.helpmsg.setReadOnly(True)
        vbox.addWidget(self.helpmsg)

        self.pinbox = QWidget()
        pinlayout = QHBoxLayout()
        self.pinbox.setLayout(pinlayout)
        self.pintxt = PasswordLineEdit()
        self.pintxt.setMaxLength(4)
        self.pintxt.returnPressed.connect(return_pin)
        pinlayout.addWidget(QLabel(_("Enter PIN:")))
        pinlayout.addWidget(self.pintxt)
        pinlayout.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        pinlayout.addStretch(1)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        vbox.addWidget(self.pinbox)

        self.cardbox = QWidget()
        card = QVBoxLayout()
        self.cardbox.setLayout(card)
        self.addrtext = QTextEdit()
        self.addrtext.setStyleSheet("QTextEdit { color:blue; background-color:lightgray; "
                                    "padding:15px 10px; border:none; font-size:20pt; }")
        self.addrtext.setReadOnly(True)
        self.addrtext.setMaximumHeight(120)
        card.addWidget(self.addrtext)

        def pin_changed(s):
            if len(s) < len(self.idxs):
                i = self.idxs[len(s)]
                addr = self.txdata['address']
                addr = addr[:i] + '<u><b>' + addr[i:i+1] + '</u></b>' + addr[i+1:]
                self.addrtext.setHtml(str(addr))
            else:
                self.addrtext.setHtml(_("Press Enter"))

        pin_changed('')
        cardpin = QHBoxLayout()
        cardpin.addWidget(QLabel(_("Enter PIN:")))
        self.cardtxt = PasswordLineEdit()
        self.cardtxt.setMaxLength(len(self.idxs))
        self.cardtxt.textChanged.connect(pin_changed)
        self.cardtxt.returnPressed.connect(return_pin)
        cardpin.addWidget(self.cardtxt)
        cardpin.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        cardpin.addStretch(1)
        card.addLayout(cardpin)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        vbox.addWidget(self.cardbox)

        self.update_dlg()

    def populate_modes(self):
        self.modes.blockSignals(True)
        self.modes.clear()
        self.modes.addItem(_("Summary Text PIN (requires dongle replugging)")
                           if self.txdata['confirmationType'] == 1 else
                           _("Summary Text PIN is Disabled"))
        if self.txdata['confirmationType'] > 1:
            self.modes.addItem(_("Security Card Challenge"))
        self.modes.blockSignals(False)

    def update_dlg(self):
        self.modes.setCurrentIndex(self.cfg['mode'])
        self.modebox.setVisible(True)
        self.helpmsg.setText(helpTxt[self.cfg['mode']])
        self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] == 1 else 100)
        self.helpmsg.setVisible(True)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        self.pintxt.setFocus(True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True)
        self.setMaximumHeight(200)

    def getDevice2FAMode(self):
        apdu = [0xe0, 0x24, 0x01, 0x00, 0x00, 0x01] # get 2fa mode
        try:
            mode = self.dongle.exchange( bytearray(apdu) )
            return mode
        except BTChipException as e:
            logger.debug('Device getMode Failed')
        return 0x11
Beispiel #10
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        centralWidget = QWidget()

        fontLabel = QLabel("Font:")
        self.fontCombo = QFontComboBox()
        sizeLabel = QLabel("Size:")
        self.sizeCombo = QComboBox()
        styleLabel = QLabel("Style:")
        self.styleCombo = QComboBox()
        fontMergingLabel = QLabel("Automatic Font Merging:")
        self.fontMerging = QCheckBox()
        self.fontMerging.setChecked(True)

        self.scrollArea = QScrollArea()
        self.characterWidget = CharacterWidget()
        self.scrollArea.setWidget(self.characterWidget)

        self.findStyles(self.fontCombo.currentFont())
        self.findSizes(self.fontCombo.currentFont())

        self.lineEdit = QLineEdit()
        clipboardButton = QPushButton("&To clipboard")

        self.clipboard = QApplication.clipboard()

        self.fontCombo.currentFontChanged.connect(self.findStyles)
        self.fontCombo.activated[str].connect(self.characterWidget.updateFont)
        self.styleCombo.activated[str].connect(self.characterWidget.updateStyle)
        self.sizeCombo.currentIndexChanged[str].connect(self.characterWidget.updateSize)
        self.characterWidget.characterSelected.connect(self.insertCharacter)
        clipboardButton.clicked.connect(self.updateClipboard)

        controlsLayout = QHBoxLayout()
        controlsLayout.addWidget(fontLabel)
        controlsLayout.addWidget(self.fontCombo, 1)
        controlsLayout.addWidget(sizeLabel)
        controlsLayout.addWidget(self.sizeCombo, 1)
        controlsLayout.addWidget(styleLabel)
        controlsLayout.addWidget(self.styleCombo, 1)
        controlsLayout.addWidget(fontMergingLabel)
        controlsLayout.addWidget(self.fontMerging, 1)
        controlsLayout.addStretch(1)

        lineLayout = QHBoxLayout()
        lineLayout.addWidget(self.lineEdit, 1)
        lineLayout.addSpacing(12)
        lineLayout.addWidget(clipboardButton)

        centralLayout = QVBoxLayout()
        centralLayout.addLayout(controlsLayout)
        centralLayout.addWidget(self.scrollArea, 1)
        centralLayout.addSpacing(4)
        centralLayout.addLayout(lineLayout)
        centralWidget.setLayout(centralLayout)

        self.setCentralWidget(centralWidget)
        self.setWindowTitle("Character Map")

    def findStyles(self, font):
        fontDatabase = QFontDatabase()
        currentItem = self.styleCombo.currentText()
        self.styleCombo.clear()

        for style in fontDatabase.styles(font.family()):
            self.styleCombo.addItem(style)

        styleIndex = self.styleCombo.findText(currentItem)
        if styleIndex == -1:
            self.styleCombo.setCurrentIndex(0)
        else:
            self.styleCombo.setCurrentIndex(styleIndex)

    def findSizes(self, font):
        fontDatabase = QFontDatabase()
        currentSize = self.sizeCombo.currentText()
        self.sizeCombo.blockSignals(True)
        self.sizeCombo.clear()

        if fontDatabase.isSmoothlyScalable(font.family(), fontDatabase.styleString(font)):
            for size in QFontDatabase.standardSizes():
                self.sizeCombo.addItem(str(size))
                self.sizeCombo.setEditable(True)
        else:
            for size in fontDatabase.smoothSizes(font.family(), fontDatabase.styleString(font)):
                self.sizeCombo.addItem(str(size))
                self.sizeCombo.setEditable(False)

        self.sizeCombo.blockSignals(False)

        sizeIndex = self.sizeCombo.findText(currentSize)
        if sizeIndex == -1:
            self.sizeCombo.setCurrentIndex(max(0, self.sizeCombo.count() / 3))
        else:
            self.sizeCombo.setCurrentIndex(sizeIndex)

    def insertCharacter(self, character):
        self.lineEdit.insert(character)

    def updateClipboard(self):
        self.clipboard.setText(self.lineEdit.text(), QClipboard.Clipboard)
        self.clipboard.setText(self.lineEdit.text(), QClipboard.Selection)
Beispiel #11
0
class ColorSet:
    """Stores color settings and provides dialogs for user changes.
    """
    def __init__(self, option):
        self.option = option
        self.sysPalette = QApplication.palette()
        self.colors = [Color(roleKey) for roleKey in roles.keys()]
        self.theme = ThemeSetting[self.option.strData('ColorTheme')]
        for color in self.colors:
            color.colorChanged.connect(self.setCustomTheme)
            color.setFromPalette(self.sysPalette)
            if self.theme == ThemeSetting.dark:
                color.setFromTheme(darkColors)
            elif self.theme == ThemeSetting.custom:
                color.setFromOption(self.option)

    def setAppColors(self):
        """Set application to current colors.
        """
        newPalette = QApplication.palette()
        for color in self.colors:
            color.updatePalette(newPalette)
        qApp.setPalette(newPalette)

    def showDialog(self, parent):
        """Show a dialog for user color changes.

        Return True if changes were made.
        """
        dialog = QDialog(parent)
        dialog.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint
                              | Qt.WindowSystemMenuHint)
        dialog.setWindowTitle(_('Color Settings'))
        topLayout = QVBoxLayout(dialog)
        dialog.setLayout(topLayout)
        themeBox = QGroupBox(_('Color Theme'), dialog)
        topLayout.addWidget(themeBox)
        themeLayout = QVBoxLayout(themeBox)
        self.themeControl = QComboBox(dialog)
        self.themeControl.addItem(_('Default system theme'),
                                  ThemeSetting.system)
        self.themeControl.addItem(_('Dark theme'), ThemeSetting.dark)
        self.themeControl.addItem(_('Custom theme'), ThemeSetting.custom)
        self.themeControl.setCurrentIndex(
            self.themeControl.findData(self.theme))
        self.themeControl.currentIndexChanged.connect(self.updateThemeSetting)
        themeLayout.addWidget(self.themeControl)
        self.groupBox = QGroupBox(dialog)
        self.setBoxTitle()
        topLayout.addWidget(self.groupBox)
        gridLayout = QGridLayout(self.groupBox)
        row = 0
        for color in self.colors:
            gridLayout.addWidget(color.getLabel(), row, 0)
            gridLayout.addWidget(color.getSwatch(), row, 1)
            row += 1
        ctrlLayout = QHBoxLayout()
        topLayout.addLayout(ctrlLayout)
        ctrlLayout.addStretch(0)
        okButton = QPushButton(_('&OK'), dialog)
        ctrlLayout.addWidget(okButton)
        okButton.clicked.connect(dialog.accept)
        cancelButton = QPushButton(_('&Cancel'), dialog)
        ctrlLayout.addWidget(cancelButton)
        cancelButton.clicked.connect(dialog.reject)
        if dialog.exec_() == QDialog.Accepted:
            self.theme = ThemeSetting(self.themeControl.currentData())
            self.option.changeData('ColorTheme', self.theme.name, True)
            if self.theme == ThemeSetting.system:
                qApp.setPalette(self.sysPalette)
            else:  # dark theme or custom
                if self.theme == ThemeSetting.custom:
                    for color in self.colors:
                        color.updateOption(self.option)
                self.setAppColors()
        else:
            for color in self.colors:
                color.setFromPalette(self.sysPalette)
                if self.theme == ThemeSetting.dark:
                    color.setFromTheme(darkColors)
                elif self.theme == ThemeSetting.custom:
                    color.setFromOption(self.option)

    def setBoxTitle(self):
        """Set title of group box to standard or custom.
        """
        if self.themeControl.currentData() == ThemeSetting.custom:
            title = _('Custom Colors')
        else:
            title = _('Theme Colors')
        self.groupBox.setTitle(title)

    def updateThemeSetting(self):
        """Update the colors based on a theme control change.
        """
        if self.themeControl.currentData() == ThemeSetting.system:
            for color in self.colors:
                color.setFromPalette(self.sysPalette)
                color.changeSwatchColor()
        elif self.themeControl.currentData() == ThemeSetting.dark:
            for color in self.colors:
                color.setFromTheme(darkColors)
                color.changeSwatchColor()
        else:
            for color in self.colors:
                color.setFromOption(self.option)
                color.changeSwatchColor()
        self.setBoxTitle()

    def setCustomTheme(self):
        """Set to custom theme setting after user color change.
        """
        if self.themeControl.currentData != ThemeSetting.custom:
            self.themeControl.blockSignals(True)
            self.themeControl.setCurrentIndex(2)
            self.themeControl.blockSignals(False)
            self.setBoxTitle()
Beispiel #12
0
class IndustrialDualAnalogInV2(COMCUPluginBase):
    def __init__(self, *args):
        super().__init__(BrickletIndustrialDualAnalogInV2, *args)

        self.analog_in = self.device

        self.cbe_voltage0 = CallbackEmulator(
            self.analog_in.get_voltage,
            0,
            self.cb_voltage,
            self.increase_error_count,
            pass_arguments_to_result_callback=True)

        self.cbe_voltage1 = CallbackEmulator(
            self.analog_in.get_voltage,
            1,
            self.cb_voltage,
            self.increase_error_count,
            pass_arguments_to_result_callback=True)

        self.calibration = None

        self.sample_rate_label = QLabel('Sample Rate:')
        self.sample_rate_combo = QComboBox()
        self.sample_rate_combo.addItem('976 Hz')
        self.sample_rate_combo.addItem('488 Hz')
        self.sample_rate_combo.addItem('244 Hz')
        self.sample_rate_combo.addItem('122 Hz')
        self.sample_rate_combo.addItem('61 Hz')
        self.sample_rate_combo.addItem('4 Hz')
        self.sample_rate_combo.addItem('2 Hz')
        self.sample_rate_combo.addItem('1 Hz')

        self.current_voltage = [CurveValueWrapper(),
                                CurveValueWrapper()]  # float, V
        self.calibration_button = QPushButton('Calibration...')

        self.sample_rate_combo.currentIndexChanged.connect(
            self.sample_rate_combo_index_changed)
        self.calibration_button.clicked.connect(
            self.calibration_button_clicked)

        plots = [
            ('Channel 0', Qt.red, self.current_voltage[0], format_voltage),
            ('Channel 1', Qt.blue, self.current_voltage[1], format_voltage)
        ]
        self.plot_widget = PlotWidget('Voltage [V]', plots, y_resolution=0.001)

        # Define lines
        line = QFrame()
        line.setObjectName("line")
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        line1 = QFrame()
        line1.setObjectName("line1")
        line1.setFrameShape(QFrame.HLine)
        line1.setFrameShadow(QFrame.Sunken)

        line2 = QFrame()
        line2.setObjectName("line2")
        line2.setFrameShape(QFrame.HLine)
        line2.setFrameShadow(QFrame.Sunken)

        # Define channel LED status config widgets
        self.led_config_ch0_label = QLabel('Channel 0')
        self.led_config_ch1_label = QLabel('Channel 1')
        self.led_config_label = QLabel('LED Config:')
        self.led_status_config_label = QLabel('LED Status Config:')
        self.led_status_config_ch0_min_label = QLabel('Min:')
        self.led_status_config_ch0_max_label = QLabel('Max:')
        self.led_status_config_ch1_min_label = QLabel('Min:')
        self.led_status_config_ch1_max_label = QLabel('Max:')

        self.led_config_ch0_combo = QComboBox()
        self.led_config_ch0_combo.addItem('Off')
        self.led_config_ch0_combo.addItem('On')
        self.led_config_ch0_combo.addItem('Show Heartbeat')
        self.led_config_ch0_combo.addItem('Show Channel Status')
        self.led_config_ch0_combo.currentIndexChanged.connect(
            self.led_config_ch0_combo_changed)

        self.led_config_ch1_combo = QComboBox()
        self.led_config_ch1_combo.addItem('Off')
        self.led_config_ch1_combo.addItem('On')
        self.led_config_ch1_combo.addItem('Show Heartbeat')
        self.led_config_ch1_combo.addItem('Show Channel Status')
        self.led_config_ch1_combo.currentIndexChanged.connect(
            self.led_config_ch1_combo_changed)

        self.led_status_config_ch0_combo = QComboBox()
        self.led_status_config_ch0_combo.addItem('Threshold')
        self.led_status_config_ch0_combo.addItem('Intensity')
        self.led_status_config_ch0_combo.currentIndexChanged.connect(
            self.led_status_config_ch0_combo_changed)

        self.led_status_config_ch1_combo = QComboBox()
        self.led_status_config_ch1_combo.addItem('Threshold')
        self.led_status_config_ch1_combo.addItem('Intensity')
        self.led_status_config_ch1_combo.currentIndexChanged.connect(
            self.led_status_config_ch1_combo_changed)

        self.led_status_config_ch0_min_sbox = QSpinBox()
        self.led_status_config_ch0_min_sbox.setMinimum(-35000)
        self.led_status_config_ch0_min_sbox.setMaximum(35000)
        self.led_status_config_ch0_min_sbox.setValue(0)
        self.led_status_config_ch0_min_sbox.setSingleStep(1)
        self.led_status_config_ch0_min_sbox.setSuffix(' mV')
        self.led_status_config_ch0_min_sbox.valueChanged.connect(
            self.led_status_config_ch0_min_sbox_changed)

        self.led_status_config_ch0_max_sbox = QSpinBox()
        self.led_status_config_ch0_max_sbox.setMinimum(-35000)
        self.led_status_config_ch0_max_sbox.setMaximum(35000)
        self.led_status_config_ch0_max_sbox.setValue(0)
        self.led_status_config_ch0_max_sbox.setSingleStep(1)
        self.led_status_config_ch0_max_sbox.setSuffix(' mV')
        self.led_status_config_ch0_max_sbox.valueChanged.connect(
            self.led_status_config_ch0_max_sbox_changed)

        self.led_status_config_ch1_min_sbox = QSpinBox()
        self.led_status_config_ch1_min_sbox.setMinimum(-35000)
        self.led_status_config_ch1_min_sbox.setMaximum(35000)
        self.led_status_config_ch1_min_sbox.setValue(0)
        self.led_status_config_ch1_min_sbox.setSingleStep(1)
        self.led_status_config_ch1_min_sbox.setSuffix(' mV')
        self.led_status_config_ch1_min_sbox.valueChanged.connect(
            self.led_status_config_ch1_min_sbox_changed)

        self.led_status_config_ch1_max_sbox = QSpinBox()
        self.led_status_config_ch1_max_sbox.setMinimum(-35000)
        self.led_status_config_ch1_max_sbox.setMaximum(35000)
        self.led_status_config_ch1_max_sbox.setValue(0)
        self.led_status_config_ch1_max_sbox.setSingleStep(1)
        self.led_status_config_ch1_max_sbox.setSuffix(' mV')
        self.led_status_config_ch1_max_sbox.valueChanged.connect(
            self.led_status_config_ch1_max_sbox_changed)

        # Define size policies
        h_sp = QSizePolicy()
        h_sp.setHorizontalPolicy(QSizePolicy.Expanding)

        # Set size policies
        self.sample_rate_combo.setSizePolicy(h_sp)
        self.led_config_ch0_combo.setSizePolicy(h_sp)
        self.led_config_ch1_combo.setSizePolicy(h_sp)
        self.led_status_config_ch0_combo.setSizePolicy(h_sp)
        self.led_status_config_ch1_combo.setSizePolicy(h_sp)
        self.led_status_config_ch0_min_sbox.setSizePolicy(h_sp)
        self.led_status_config_ch0_max_sbox.setSizePolicy(h_sp)
        self.led_status_config_ch1_min_sbox.setSizePolicy(h_sp)
        self.led_status_config_ch1_max_sbox.setSizePolicy(h_sp)

        # Define layouts
        hlayout = QHBoxLayout()
        vlayout = QVBoxLayout()
        glayout = QGridLayout()
        layout = QVBoxLayout(self)
        hlayout_ch0_min_max = QHBoxLayout()
        hlayout_ch1_min_max = QHBoxLayout()

        # Populate layouts
        vlayout.addWidget(self.calibration_button)
        hlayout.addWidget(self.sample_rate_label)
        hlayout.addWidget(self.sample_rate_combo)
        vlayout.addLayout(hlayout)
        vlayout.addWidget(line1)

        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_min_label)
        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_min_sbox)
        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_max_label)
        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_max_sbox)

        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_min_label)
        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_min_sbox)
        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_max_label)
        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_max_sbox)

        glayout.addWidget(self.led_config_ch0_label, 0, 1, 1,
                          1)  # R, C, RS, CS
        glayout.addWidget(self.led_config_ch1_label, 0, 2, 1, 1)

        glayout.addWidget(line2, 1, 0, 1, 3)

        glayout.addWidget(self.led_config_label, 2, 0, 1, 1)
        glayout.addWidget(self.led_config_ch0_combo, 2, 1, 1, 1)
        glayout.addWidget(self.led_config_ch1_combo, 2, 2, 1, 1)

        glayout.addWidget(self.led_status_config_label, 3, 0, 1, 1)
        glayout.addWidget(self.led_status_config_ch0_combo, 3, 1, 1, 1)
        glayout.addWidget(self.led_status_config_ch1_combo, 3, 2, 1, 1)

        glayout.addLayout(hlayout_ch0_min_max, 4, 1, 1, 1)
        glayout.addLayout(hlayout_ch1_min_max, 4, 2, 1, 1)

        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(vlayout)
        layout.addLayout(glayout)

        self.ui_group_ch_status_ch0 = [
            self.led_status_config_ch0_combo,
            self.led_status_config_ch0_min_sbox,
            self.led_status_config_ch0_max_sbox
        ]

        self.ui_group_ch_status_ch1 = [
            self.led_status_config_ch1_combo,
            self.led_status_config_ch1_min_sbox,
            self.led_status_config_ch1_max_sbox
        ]

    def start(self):
        async_call(self.analog_in.get_sample_rate, None,
                   self.get_sample_rate_async, self.increase_error_count)

        for channel in range(2):
            async_call(self.analog_in.get_channel_led_config,
                       channel,
                       self.get_channel_led_config_async,
                       self.increase_error_count,
                       pass_arguments_to_result_callback=True)
            async_call(self.analog_in.get_channel_led_status_config,
                       channel,
                       self.get_channel_led_status_config_async,
                       self.increase_error_count,
                       pass_arguments_to_result_callback=True)

        self.cbe_voltage0.set_period(100)
        self.cbe_voltage1.set_period(100)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_voltage0.set_period(0)
        self.cbe_voltage1.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        if self.calibration != None:
            self.calibration.close()

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialDualAnalogInV2.DEVICE_IDENTIFIER

    def calibration_button_clicked(self):
        if self.calibration == None:
            self.calibration = Calibration(self)

        self.calibration_button.setEnabled(False)
        self.calibration.show()

    def sample_rate_combo_index_changed(self, index):
        async_call(self.analog_in.set_sample_rate, index, None,
                   self.increase_error_count)

    def led_config_ch0_combo_changed(self, index):
        if index != self.analog_in.CHANNEL_LED_CONFIG_SHOW_CHANNEL_STATUS:
            for e in self.ui_group_ch_status_ch0:
                e.setEnabled(False)
        else:
            for e in self.ui_group_ch_status_ch0:
                e.setEnabled(True)

        self.analog_in.set_channel_led_config(0, index)

    def led_config_ch1_combo_changed(self, index):
        if index != self.analog_in.CHANNEL_LED_CONFIG_SHOW_CHANNEL_STATUS:
            for e in self.ui_group_ch_status_ch1:
                e.setEnabled(False)
        else:
            for e in self.ui_group_ch_status_ch1:
                e.setEnabled(True)

        self.analog_in.set_channel_led_config(1, index)

    def led_status_config_ch0_combo_changed(self, index):
        self.analog_in.set_channel_led_status_config(
            0, self.led_status_config_ch0_min_sbox.value(),
            self.led_status_config_ch0_max_sbox.value(), index)

    def led_status_config_ch1_combo_changed(self, index):
        self.analog_in.set_channel_led_status_config(
            1, self.led_status_config_ch1_min_sbox.value(),
            self.led_status_config_ch1_max_sbox.value(), index)

    def led_status_config_ch0_min_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(
            0, self.led_status_config_ch0_min_sbox.value(),
            self.led_status_config_ch0_max_sbox.value(),
            self.led_status_config_ch0_combo.currentIndex())

    def led_status_config_ch0_max_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(
            0, self.led_status_config_ch0_min_sbox.value(),
            self.led_status_config_ch0_max_sbox.value(),
            self.led_status_config_ch0_combo.currentIndex())

    def led_status_config_ch1_min_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(
            1, self.led_status_config_ch1_min_sbox.value(),
            self.led_status_config_ch1_max_sbox.value(),
            self.led_status_config_ch1_combo.currentIndex())

    def led_status_config_ch1_max_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(
            1, self.led_status_config_ch1_min_sbox.value(),
            self.led_status_config_ch1_max_sbox.value(),
            self.led_status_config_ch1_combo.currentIndex())

    def get_voltage_value0(self):
        return self.voltage_value[0]

    def get_voltage_value1(self):
        return self.voltage_value[1]

    def get_sample_rate_async(self, rate):
        self.sample_rate_combo.blockSignals(True)

        self.sample_rate_combo.setCurrentIndex(rate)

        self.sample_rate_combo.blockSignals(False)

    def get_channel_led_config_async(self, channel, config):
        self.led_config_ch0_combo.blockSignals(True)
        self.led_config_ch1_combo.blockSignals(True)

        if channel == 0:
            self.led_config_ch0_combo.setCurrentIndex(config)
        elif channel == 1:
            self.led_config_ch1_combo.setCurrentIndex(config)

        self.led_config_ch0_combo.blockSignals(False)
        self.led_config_ch1_combo.blockSignals(False)

    def get_channel_led_status_config_async(self, channel, config):
        self.led_status_config_ch0_combo.blockSignals(True)
        self.led_status_config_ch1_combo.blockSignals(True)

        if channel == 0:
            self.led_status_config_ch0_combo.setCurrentIndex(config.config)
            self.led_status_config_ch0_max_sbox.setValue(config.max)
            self.led_status_config_ch0_min_sbox.setValue(config.min)
        elif channel == 1:
            self.led_status_config_ch1_combo.setCurrentIndex(config.config)
            self.led_status_config_ch1_max_sbox.setValue(config.max)
            self.led_status_config_ch1_min_sbox.setValue(config.min)

        self.led_status_config_ch0_combo.blockSignals(False)
        self.led_status_config_ch1_combo.blockSignals(False)

    def cb_voltage(self, sensor, voltage):
        self.current_voltage[sensor].value = voltage / 1000.0
Beispiel #13
0
class ConditionDialog(QDialog):
    """Dialog for defining field condition tests.

    Used for defining conditional types (modal), for finding by condition
    (nonmodal) and for filtering by condition (nonmodal).
    """
    dialogShown = pyqtSignal(bool)

    def __init__(self, dialogType, caption, nodeFormat=None, parent=None):
        """Create the conditional dialog.

        Arguments:
            dialogType -- either typeDialog, findDialog or filterDialog
            caption -- the window title for this dialog
            nodeFormat -- the current node format for the typeDialog
            parent -- the parent overall dialog
        """
        super().__init__(parent)
        self.setWindowTitle(caption)
        self.dialogType = dialogType
        self.ruleList = []
        self.combiningBoxes = []
        self.typeCombo = None
        self.resultLabel = None
        self.endFilterButton = None
        self.fieldNames = []
        if nodeFormat:
            self.fieldNames = nodeFormat.fieldNames()
        topLayout = QVBoxLayout(self)

        if dialogType == FindDialogType.typeDialog:
            self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint
                                | Qt.WindowCloseButtonHint)
        else:
            self.setAttribute(Qt.WA_QuitOnClose, False)
            self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
            typeBox = QGroupBox(_('Node Type'))
            topLayout.addWidget(typeBox)
            typeLayout = QVBoxLayout(typeBox)
            self.typeCombo = QComboBox()
            typeLayout.addWidget(self.typeCombo)
            self.typeCombo.currentIndexChanged.connect(self.updateDataType)

        self.mainLayout = QVBoxLayout()
        topLayout.addLayout(self.mainLayout)

        upCtrlLayout = QHBoxLayout()
        topLayout.addLayout(upCtrlLayout)
        addButton = QPushButton(_('&Add New Rule'))
        upCtrlLayout.addWidget(addButton)
        addButton.clicked.connect(self.addNewRule)
        self.removeButton = QPushButton(_('&Remove Rule'))
        upCtrlLayout.addWidget(self.removeButton)
        self.removeButton.clicked.connect(self.removeRule)
        upCtrlLayout.addStretch()

        if dialogType == FindDialogType.typeDialog:
            okButton = QPushButton(_('&OK'))
            upCtrlLayout.addWidget(okButton)
            okButton.clicked.connect(self.accept)
            cancelButton = QPushButton(_('&Cancel'))
            upCtrlLayout.addWidget(cancelButton)
            cancelButton.clicked.connect(self.reject)
        else:
            self.removeButton.setEnabled(False)
            saveBox = QGroupBox(_('Saved Rules'))
            topLayout.addWidget(saveBox)
            saveLayout = QVBoxLayout(saveBox)
            self.saveListBox = SmallListWidget()
            saveLayout.addWidget(self.saveListBox)
            self.saveListBox.itemDoubleClicked.connect(self.loadSavedRule)
            nameLayout = QHBoxLayout()
            saveLayout.addLayout(nameLayout)
            label = QLabel(_('Name:'))
            nameLayout.addWidget(label)
            self.saveNameEdit = QLineEdit()
            nameLayout.addWidget(self.saveNameEdit)
            self.saveNameEdit.textChanged.connect(self.updateSaveEnable)
            saveButtonLayout = QHBoxLayout()
            saveLayout.addLayout(saveButtonLayout)
            self.loadSavedButton = QPushButton(_('&Load'))
            saveButtonLayout.addWidget(self.loadSavedButton)
            self.loadSavedButton.clicked.connect(self.loadSavedRule)
            self.saveButton = QPushButton(_('&Save'))
            saveButtonLayout.addWidget(self.saveButton)
            self.saveButton.clicked.connect(self.saveRule)
            self.saveButton.setEnabled(False)
            self.delSavedButton = QPushButton(_('&Delete'))
            saveButtonLayout.addWidget(self.delSavedButton)
            self.delSavedButton.clicked.connect(self.deleteRule)
            saveButtonLayout.addStretch()

            if dialogType == FindDialogType.findDialog:
                self.resultLabel = QLabel()
                topLayout.addWidget(self.resultLabel)
            lowCtrlLayout = QHBoxLayout()
            topLayout.addLayout(lowCtrlLayout)
            if dialogType == FindDialogType.findDialog:
                previousButton = QPushButton(_('Find &Previous'))
                lowCtrlLayout.addWidget(previousButton)
                previousButton.clicked.connect(self.findPrevious)
                nextButton = QPushButton(_('Find &Next'))
                nextButton.setDefault(True)
                lowCtrlLayout.addWidget(nextButton)
                nextButton.clicked.connect(self.findNext)
            else:
                filterButton = QPushButton(_('&Filter'))
                lowCtrlLayout.addWidget(filterButton)
                filterButton.clicked.connect(self.startFilter)
                self.endFilterButton = QPushButton(_('&End Filter'))
                lowCtrlLayout.addWidget(self.endFilterButton)
                self.endFilterButton.setEnabled(False)
                self.endFilterButton.clicked.connect(self.endFilter)
            lowCtrlLayout.addStretch()
            closeButton = QPushButton(_('&Close'))
            lowCtrlLayout.addWidget(closeButton)
            closeButton.clicked.connect(self.close)
            origTypeName = nodeFormat.name if nodeFormat else ''
            self.loadTypeNames(origTypeName)
            self.loadSavedNames()
        self.ruleList.append(ConditionRule(1, self.fieldNames))
        self.mainLayout.addWidget(self.ruleList[0])

    def addNewRule(self, checked=False, combineBool='and'):
        """Add a new empty rule to the dialog.

        Arguments:
            checked -- unused placekeeper variable for signal
            combineBool -- the boolean op for combining with the previous rule
        """
        if self.ruleList:
            boolBox = QComboBox()
            boolBox.setEditable(False)
            self.combiningBoxes.append(boolBox)
            boolBox.addItems([_(op) for op in _boolOper])
            if combineBool != 'and':
                boolBox.setCurrentIndex(1)
            self.mainLayout.insertWidget(
                len(self.ruleList) * 2 - 1, boolBox, 0, Qt.AlignHCenter)
        rule = ConditionRule(len(self.ruleList) + 1, self.fieldNames)
        self.ruleList.append(rule)
        self.mainLayout.insertWidget(len(self.ruleList) * 2 - 2, rule)
        self.removeButton.setEnabled(True)

    def removeRule(self):
        """Remove the last rule from the dialog.
        """
        if self.ruleList:
            if self.combiningBoxes:
                self.combiningBoxes[-1].hide()
                del self.combiningBoxes[-1]
            self.ruleList[-1].hide()
            del self.ruleList[-1]
            if self.dialogType == FindDialogType.typeDialog:
                self.removeButton.setEnabled(len(self.ruleList) > 0)
            else:
                self.removeButton.setEnabled(len(self.ruleList) > 1)

    def clearRules(self):
        """Remove all rules from the dialog and add default rule.
        """
        for box in self.combiningBoxes:
            box.hide()
        for rule in self.ruleList:
            rule.hide()
        self.combiningBoxes = []
        self.ruleList = [ConditionRule(1, self.fieldNames)]
        self.mainLayout.insertWidget(0, self.ruleList[0])
        self.removeButton.setEnabled(True)

    def setCondition(self, conditional, typeName=''):
        """Set rule values to match the given conditional.

        Arguments:
            conditional -- the Conditional class to match
            typeName -- an optional type name used with some dialog types
        """
        if self.typeCombo:
            if typeName:
                self.typeCombo.setCurrentIndex(
                    self.typeCombo.findText(typeName))
            else:
                self.typeCombo.setCurrentIndex(0)
        while len(self.ruleList) > 1:
            self.removeRule()
        if conditional:
            self.ruleList[0].setCondition(conditional.conditionLines[0])
        for conditionLine in conditional.conditionLines[1:]:
            self.addNewRule(combineBool=conditionLine.boolOper)
            self.ruleList[-1].setCondition(conditionLine)

    def conditional(self):
        """Return a Conditional instance for the current settings.
        """
        combineBools = [0] + [
            boolBox.currentIndex() for boolBox in self.combiningBoxes
        ]
        typeName = self.typeCombo.currentText() if self.typeCombo else ''
        if typeName == _allTypeEntry:
            typeName = ''
        conditional = Conditional('', typeName)
        for boolIndex, rule in zip(combineBools, self.ruleList):
            condition = rule.conditionLine()
            if boolIndex != 0:
                condition.boolOper = 'or'
            conditional.conditionLines.append(condition)
        return conditional

    def loadTypeNames(self, origTypeName=''):
        """Load format type names into combo box.

        Arguments:
            origTypeName -- a starting type name if given
        """
        if not origTypeName:
            origTypeName = self.typeCombo.currentText()
        nodeFormats = globalref.mainControl.activeControl.structure.treeFormats
        self.typeCombo.blockSignals(True)
        self.typeCombo.clear()
        self.typeCombo.addItem(_allTypeEntry)
        typeNames = nodeFormats.typeNames()
        self.typeCombo.addItems(typeNames)
        if origTypeName and origTypeName != _allTypeEntry:
            try:
                self.typeCombo.setCurrentIndex(
                    typeNames.index(origTypeName) + 1)
            except ValueError:
                if self.endFilterButton and self.endFilterButton.isEnabled():
                    self.endFilter()
                self.clearRules()
        self.typeCombo.blockSignals(False)
        self.updateDataType()

    def updateDataType(self):
        """Update the node format based on a data type change.
        """
        typeName = self.typeCombo.currentText()
        if not typeName:
            return
        nodeFormats = globalref.mainControl.activeControl.structure.treeFormats
        if typeName == _allTypeEntry:
            fieldNameSet = set()
            for typeFormat in nodeFormats.values():
                fieldNameSet.update(typeFormat.fieldNames())
            self.fieldNames = sorted(list(fieldNameSet))
        else:
            self.fieldNames = nodeFormats[typeName].fieldNames()
        for rule in self.ruleList:
            currentField = rule.conditionLine().fieldName
            if currentField not in self.fieldNames:
                if self.endFilterButton and self.endFilterButton.isEnabled():
                    self.endFilter()
                self.clearRules()
                break
            rule.reloadFieldBox(self.fieldNames, currentField)

    def loadSavedNames(self, updateOtherDialog=False):
        """Refresh the list of saved rule names.
        """
        selNum = 0
        if self.saveListBox.count():
            selNum = self.saveListBox.currentRow()
        self.saveListBox.clear()
        nodeFormats = globalref.mainControl.activeControl.structure.treeFormats
        savedRules = nodeFormats.savedConditions()
        ruleNames = sorted(list(savedRules.keys()))
        if ruleNames:
            self.saveListBox.addItems(ruleNames)
            if selNum >= len(ruleNames):
                selNum = len(ruleNames) - 1
            self.saveListBox.setCurrentRow(selNum)
        self.loadSavedButton.setEnabled(len(ruleNames) > 0)
        self.delSavedButton.setEnabled(len(ruleNames) > 0)
        if updateOtherDialog:
            if (self != globalref.mainControl.findConditionDialog
                    and globalref.mainControl.findConditionDialog
                    and globalref.mainControl.findConditionDialog.isVisible()):
                globalref.mainControl.findConditionDialog.loadSavedNames()
            elif (self != globalref.mainControl.filterConditionDialog
                  and globalref.mainControl.filterConditionDialog
                  and globalref.mainControl.filterConditionDialog.isVisible()):
                globalref.mainControl.filterConditionDialog.loadSavedNames()

    def updateSaveEnable(self):
        """Set the save rule button enabled based on save name entry.
        """
        self.saveButton.setEnabled(len(self.saveNameEdit.text()))

    def updateFilterControls(self):
        """Set filter button status based on active window changes.
        """
        window = globalref.mainControl.activeControl.activeWindow
        if window.treeFilterView:
            filterView = window.treeFilterView
            conditional = filterView.conditionalFilter
            self.setCondition(conditional, conditional.origNodeFormatName)
            self.endFilterButton.setEnabled(True)
        else:
            self.endFilterButton.setEnabled(False)

    def loadSavedRule(self):
        """Load the current saved rule into the dialog.
        """
        nodeFormats = globalref.mainControl.activeControl.structure.treeFormats
        savedRules = nodeFormats.savedConditions()
        ruleName = self.saveListBox.currentItem().text()
        conditional = savedRules[ruleName]
        self.setCondition(conditional, conditional.origNodeFormatName)

    def saveRule(self):
        """Save the current rule settings.
        """
        name = self.saveNameEdit.text()
        self.saveNameEdit.setText('')
        treeStructure = globalref.mainControl.activeControl.structure
        undo.FormatUndo(treeStructure.undoList, treeStructure.treeFormats,
                        treeformats.TreeFormats())
        typeName = self.typeCombo.currentText()
        if typeName == _allTypeEntry:
            nodeFormat = treeStructure.treeFormats
        else:
            nodeFormat = treeStructure.treeFormats[typeName]
        nodeFormat.savedConditionText[name] = (
            self.conditional().conditionStr())
        self.loadSavedNames(True)
        self.saveListBox.setCurrentItem(
            self.saveListBox.findItems(name, Qt.MatchExactly)[0])
        globalref.mainControl.activeControl.setModified()

    def deleteRule(self):
        """Remove the current saved rule.
        """
        treeStructure = globalref.mainControl.activeControl.structure
        nodeFormats = treeStructure.treeFormats
        undo.FormatUndo(treeStructure.undoList, nodeFormats,
                        treeformats.TreeFormats())
        savedRules = nodeFormats.savedConditions()
        ruleName = self.saveListBox.currentItem().text()
        conditional = savedRules[ruleName]
        if conditional.origNodeFormatName:
            typeFormat = nodeFormats[conditional.origNodeFormatName]
            del typeFormat.savedConditionText[ruleName]
        else:
            del nodeFormats.savedConditionText[ruleName]
        self.loadSavedNames(True)
        globalref.mainControl.activeControl.setModified()

    def find(self, forward=True):
        """Find another match in the indicated direction.

        Arguments:
            forward -- next if True, previous if False
        """
        self.resultLabel.setText('')
        conditional = self.conditional()
        control = globalref.mainControl.activeControl
        if not control.findNodesByCondition(conditional, forward):
            self.resultLabel.setText(_('No conditional matches were found'))

    def findPrevious(self):
        """Find the previous match.
        """
        self.find(False)

    def findNext(self):
        """Find the next match.
        """
        self.find(True)

    def startFilter(self):
        """Start filtering nodes.
        """
        window = globalref.mainControl.activeControl.activeWindow
        filterView = window.filterView()
        filterView.conditionalFilter = self.conditional()
        filterView.updateContents()
        self.endFilterButton.setEnabled(True)

    def endFilter(self):
        """Stop filtering nodes.
        """
        window = globalref.mainControl.activeControl.activeWindow
        window.removeFilterView()
        self.endFilterButton.setEnabled(False)

    def closeEvent(self, event):
        """Signal that the dialog is closing.

        Arguments:
            event -- the close event
        """
        self.dialogShown.emit(False)
Beispiel #14
0
class AccountDialog(QDialog):
    selected = QtCore.pyqtSignal(int, bool)
    aborted = QtCore.pyqtSignal()

    def __init__(self, parent, accountman):
        QDialog.__init__(self, parent)

        self.accountman = accountman

        layout = QVBoxLayout()

        self.setWindowTitle('Select Account')

        # Create list
        self.table = QTableWidget()
        self.table.horizontalHeader().setHighlightSections(False)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.verticalHeader().hide()
        self.table.setGridStyle(QtCore.Qt.NoPen)
        self.table.doubleClicked.connect(self.select)

        bottom_layout = QHBoxLayout()
        self.remember_chk = QCheckBox('Remember')
        cancel_btn = QPushButton('Cancel')
        cancel_btn.clicked.connect(self.cancel)
        add_btn = QPushButton('Add')
        add_btn.clicked.connect(self.add)
        self.edit_btns = QComboBox()
        self.edit_btns.blockSignals(True)
        self.edit_btns.addItem('Edit...')
        self.edit_btns.addItem('Update')
        self.edit_btns.addItem('Delete')
        self.edit_btns.addItem('Purge')
        self.edit_btns.setItemData(1, 'Change the local password/PIN for this account', QtCore.Qt.ToolTipRole)
        self.edit_btns.setItemData(2, 'Remove this account from Trackma', QtCore.Qt.ToolTipRole)
        self.edit_btns.setItemData(3, 'Clear local DB for this account', QtCore.Qt.ToolTipRole)
        self.edit_btns.setCurrentIndex(0)
        self.edit_btns.blockSignals(False)
        self.edit_btns.activated.connect(self.s_edit)
        select_btn = QPushButton('Select')
        select_btn.clicked.connect(self.select)
        select_btn.setDefault(True)
        bottom_layout.addWidget(self.remember_chk)
        bottom_layout.addWidget(cancel_btn)
        bottom_layout.addWidget(add_btn)
        bottom_layout.addWidget(self.edit_btns)
        bottom_layout.addWidget(select_btn)

        # Get icons
        self.icons = dict()
        for libname, lib in utils.available_libs.items():
            self.icons[libname] = QtGui.QIcon(lib[1])

        # Populate list
        self.update()
        self.rebuild()

        # Finish layout
        layout.addWidget(self.table)
        layout.addLayout(bottom_layout)
        self.setLayout(layout)

    def update(self):
        self.remember_chk.setChecked(self.accountman.get_default() is not None)

    def add(self):
        result = AccountAddDialog.do(icons=self.icons)
        if result:
            (username, password, api) = result
            self.accountman.add_account(username, password, api)
            self.rebuild()

    def edit(self):
        self.edit_btns.blockSignals(True)
        self.edit_btns.setCurrentIndex(0)
        self.edit_btns.blockSignals(False)
        try:
            selected_account_num = self.table.selectedItems()[0].num
            acct = self.accountman.get_account(selected_account_num)
            result = AccountAddDialog.do(icons=self.icons,
                                         edit=True,
                                         username=acct['username'],
                                         password=acct['password'],
                                         api=acct['api'])
            if result:
                (username, password, api) = result
                self.accountman.edit_account(selected_account_num, username, password, api)
                self.rebuild()
        except IndexError:
            self._error("Please select an account.")

    def delete(self):
        try:
            selected_account_num = self.table.selectedItems()[0].num
            reply = QMessageBox.question(self, 'Confirmation', 'Do you want to delete the selected account?', QMessageBox.Yes, QMessageBox.No)

            if reply == QMessageBox.Yes:
                self.accountman.delete_account(selected_account_num)
                self.rebuild()
        except IndexError:
            self._error("Please select an account.")

    def purge(self):
        try:
            selected_account_num = self.table.selectedItems()[0].num
            reply = QMessageBox.question(self, 'Confirmation', 'Do you want to purge the selected account\'s local data?', QMessageBox.Yes, QMessageBox.No)

            if reply == QMessageBox.Yes:
                self.accountman.purge_account(selected_account_num)
                self.rebuild()
        except IndexError:
            self._error("Please select an account.")

    def s_edit(self, index):
        if   index is 1:
            self.edit()
        elif index is 2:
            self.delete()
        elif index is 3:
            self.purge()

    def rebuild(self):
        self.table.clear()

        columns = ['Username', 'Site']
        self.table.setColumnCount(len(columns))
        self.table.setHorizontalHeaderLabels(columns)
        self.table.setRowCount(len(self.accountman.accounts['accounts']))

        accounts = self.accountman.get_accounts()
        i = 0
        for k, account in accounts:
            self.table.setRowHeight(i, QtGui.QFontMetrics(self.table.font()).height() + 2)
            self.table.setItem(i, 0, AccountItem(k, account['username']))
            self.table.setItem(i, 1, AccountItem(k, account['api'], self.icons.get(account['api'])))

            i += 1

        if pyqt_version is 5:
            self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        else:
            self.table.horizontalHeader().setResizeMode(0, QHeaderView.Stretch)

    def select(self, checked):
        try:
            selected_account_num = self.table.selectedItems()[0].num
            self.selected.emit(selected_account_num, self.remember_chk.isChecked())
            self.close()
        except IndexError:
            self._error("Please select an account.")

    def cancel(self, checked):
        self.aborted.emit()
        self.close()

    def _error(self, msg):
        QMessageBox.critical(self, 'Error', str(msg), QMessageBox.Ok)
Beispiel #15
0
class FontToolBar(QToolBar):

    def __init__(self, pointSize, parent=None):
        super(FontToolBar, self).__init__(parent)
        auxiliaryWidth = self.fontMetrics().width('0') * 8
        self.leftTextField = QLineEdit(self)
        self.leftTextField.setMaximumWidth(auxiliaryWidth)
        self.textField = QComboBox(self)
        self.textField.setEditable(True)
        completer = self.textField.completer()
        completer.setCaseSensitivity(Qt.CaseSensitive)
        self.textField.setCompleter(completer)
        # XXX: had to use Maximum because Preferred did entend the widget(?)
        self.textField.setSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Maximum)
        items = QSettings().value("metricsWindow/comboBoxItems", comboBoxItems,
                                  str)
        self.textField.addItems(items)
        self.rightTextField = QLineEdit(self)
        self.rightTextField.setMaximumWidth(auxiliaryWidth)
        self.leftTextField.textEdited.connect(self.textField.editTextChanged)
        self.rightTextField.textEdited.connect(self.textField.editTextChanged)
        self.comboBox = QComboBox(self)
        self.comboBox.setEditable(True)
        self.comboBox.setValidator(QIntValidator(self))
        for p in pointSizes:
            self.comboBox.addItem(str(p))
        self.comboBox.setEditText(str(pointSize))

        self.configBar = QPushButton(self)
        self.configBar.setFlat(True)
        self.configBar.setIcon(QIcon(":/resources/settings.svg"))
        self.configBar.setStyleSheet("padding: 2px 0px; padding-right: 10px")
        self.toolsMenu = QMenu(self)
        showKerning = self.toolsMenu.addAction(
            "Show Kerning", self.showKerning)
        showKerning.setCheckable(True)
        showMetrics = self.toolsMenu.addAction(
            "Show Metrics", self.showMetrics)
        showMetrics.setCheckable(True)
        self.toolsMenu.addSeparator()
        wrapLines = self.toolsMenu.addAction("Wrap lines", self.wrapLines)
        wrapLines.setCheckable(True)
        noWrapLines = self.toolsMenu.addAction("No wrap", self.noWrapLines)
        noWrapLines.setCheckable(True)
        self.toolsMenu.addSeparator()
        verticalFlip = self.toolsMenu.addAction(
            "Vertical flip", self.verticalFlip)
        verticalFlip.setCheckable(True)
        """
        lineHeight = QWidgetAction(self.toolsMenu)
        lineHeight.setText("Line height:")
        lineHeightSlider = QSlider(Qt.Horizontal, self)
        # QSlider works with integers so we'll just divide by 100 what comes
        # out of it
        lineHeightSlider.setMinimum(80)
        lineHeightSlider.setMaximum(160)
        lineHeightSlider.setValue(100)
        #lineHeightSlider.setContentsMargins(30, 0, 30, 0)
        lineHeightSlider.valueChanged.connect(self.lineHeight)
        lineHeight.setDefaultWidget(lineHeightSlider)
        self.toolsMenu.addAction(lineHeight)
        """

        wrapLinesGroup = QActionGroup(self)
        wrapLinesGroup.addAction(wrapLines)
        wrapLinesGroup.addAction(noWrapLines)
        wrapLines.setChecked(True)
        # self.toolsMenu.setActiveAction(wrapLines)
        self.configBar.setMenu(self.toolsMenu)

        self.addWidget(self.leftTextField)
        self.addWidget(self.textField)
        self.addWidget(self.rightTextField)
        self.addWidget(self.comboBox)
        self.addWidget(self.configBar)

    def showEvent(self, event):
        super(FontToolBar, self).showEvent(event)
        self.textField.setFocus(True)

    def setPointSize(self, pointSize):
        self.comboBox.blockSignals(True)
        self.comboBox.setEditText(str(pointSize))
        self.comboBox.blockSignals(False)

    def showKerning(self):
        action = self.sender()
        self.parent().canvas.setShowKerning(action.isChecked())

    def showMetrics(self):
        action = self.sender()
        self.parent().canvas.setShowMetrics(action.isChecked())

    def verticalFlip(self):
        action = self.sender()
        self.parent().canvas.setVerticalFlip(action.isChecked())

    def lineHeight(self, value):
        self.parent().canvas.setLineHeight(value / 100)

    def wrapLines(self):
        self.parent().canvas.setWrapLines(True)

    def noWrapLines(self):
        self.parent().canvas.setWrapLines(False)
class StandardLibraryPage(QSplitter):
    """ The GUI for the standard library page of a project. """

    # The page's label.
    label = "Standard Library"

    @property
    def project(self):
        """ The project property getter. """

        return self._project

    @project.setter
    def project(self, value):
        """ The project property setter. """

        if self._project != value:
            self._project = value

            self._update_page()

    def __init__(self):
        """ Initialise the page. """

        super().__init__()

        self._project = None

        # Create the page's GUI.
        stdlib_pane = QWidget()
        stdlib_layout = QVBoxLayout()

        self._stdlib_edit = QTreeWidget(
                whatsThis="This shows the packages and modules in the target "
                        "Python version's standard library. Check those "
                        "packages and modules that are explicitly imported by "
                        "the application. A module will be partially checked "
                        "(and automatically included) if another module "
                        "requires it.")
        self._stdlib_edit.setHeaderLabels(["Package"])
        self._stdlib_edit.itemChanged.connect(self._module_changed)

        stdlib_layout.addWidget(self._stdlib_edit)

        stdlib_pane.setLayout(stdlib_layout)
        self.addWidget(stdlib_pane)

        extlib_pane = QWidget()
        extlib_layout = QVBoxLayout()
        extlib_sublayout = QFormLayout()

        self._version_edit = QComboBox(
                whatsThis="Select the target Python version. This will cause "
                        "the standard library package hierarchy to be "
                        "updated.")
        self._version_edit.addItems(get_supported_python_versions())
        self._version_edit.currentIndexChanged.connect(self._version_changed)
        extlib_sublayout.addRow("Target Python version", self._version_edit)

        self._ssl_edit = QCheckBox(
                whatsThis="Enable SSL for the standard library modules "
                        "that have optional support for it.",
                stateChanged=self._ssl_changed)
        extlib_sublayout.addRow("Enable optional SSL support", self._ssl_edit)

        extlib_layout.addLayout(extlib_sublayout)

        plat_gb = QGroupBox("Use standard Python shared library")
        plat_gb_layout = QVBoxLayout()
        self._platform_buttons = []

        for scope, plat, subscopes in PLATFORM_SCOPES:
            plat_cb = QCheckBox(plat,
                    whatsThis="Enable the use of the standard Python shared "
                            "library on {0} rather than a statically compiled "
                            "library.".format(plat),
                    stateChanged=self._platforms_changed)
            plat_cb._scope = scope
            plat_gb_layout.addWidget(plat_cb)
            self._platform_buttons.append(plat_cb)

        plat_gb.setLayout(plat_gb_layout)
        extlib_layout.addWidget(plat_gb)

        self._extlib_edit = QTreeView(
                whatsThis="This is the list of external libraries that must "
                        "be linked with the application. A library will only "
                        "be enabled if a module in the standard library uses "
                        "it. Double-click in the <b>DEFINES</b>, "
                        "<b>INCLUDEPATH</b> and <b>LIBS</b> columns to modify "
                        "the corresponding <tt>qmake</tt> variable as "
                        "required. Values may be prefixed by a platform "
                        "specific <tt>qmake</tt> scope.")
        self._extlib_edit.setRootIsDecorated(False)
        self._extlib_edit.setEditTriggers(
                QTreeView.DoubleClicked|QTreeView.SelectedClicked|
                QTreeView.EditKeyPressed)

        model = QStandardItemModel(self._extlib_edit)
        model.setHorizontalHeaderLabels(
                ("External Library", 'DEFINES', 'INCLUDEPATH', 'LIBS'))
        model.itemChanged.connect(self._extlib_changed)

        for extlib in external_libraries_metadata:
            name_itm = QStandardItem(extlib.user_name)

            extlib._items = (name_itm, QStandardItem(), QStandardItem(),
                    QStandardItem())

            model.appendRow(extlib._items)

        self._extlib_edit.setModel(model)

        for col in range(3):
            self._extlib_edit.resizeColumnToContents(col)

        extlib_layout.addWidget(self._extlib_edit)

        self._ignore_extlib_changes = False

        extlib_pane.setLayout(extlib_layout)
        self.addWidget(extlib_pane)

    def _update_page(self):
        """ Update the page using the current project. """

        project = self.project

        blocked = self._version_edit.blockSignals(True)
        self._version_edit.setCurrentIndex(
                get_supported_python_version_index(
                        project.python_target_version))
        self._version_edit.blockSignals(blocked)

        blocked = self._ssl_edit.blockSignals(True)
        self._ssl_edit.setCheckState(
                Qt.Checked if project.python_ssl else Qt.Unchecked)
        self._ssl_edit.blockSignals(blocked)

        for plat in self._platform_buttons:
            blocked = plat.blockSignals(True)
            plat.setCheckState(
                    Qt.Checked if plat._scope in project.python_use_platform
                            else Qt.Unchecked)
            plat.blockSignals(blocked)

        self._update_extlib_editor()
        self._update_stdlib_editor()

    def _update_stdlib_editor(self):
        """ Update the standard library module editor. """

        project = self.project
        editor = self._stdlib_edit

        metadata = get_python_metadata(project.python_target_version)

        blocked = editor.blockSignals(True)

        editor.clear()

        def add_module(name, module, parent):
            itm = QTreeWidgetItem(parent, name.split('.')[-1:])
            itm.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable)
            itm._name = name

            # Handle any sub-modules.
            if module.modules is not None:
                for submodule_name in module.modules:
                    # We assume that a missing sub-module is because it is not
                    # in the current version rather than bad meta-data.
                    submodule = metadata.get(submodule_name)
                    if submodule is not None:
                        add_module(submodule_name, submodule, itm)

        for name, module in metadata.items():
            if not module.internal and '.' not in name:
                add_module(name, module, editor)

        editor.sortItems(0, Qt.AscendingOrder)

        editor.blockSignals(blocked)

        self._set_dependencies()

    def _set_dependencies(self):
        """ Set the dependency information. """

        project = self.project
        editor = self._stdlib_edit

        required_modules, required_libraries = project.get_stdlib_requirements()

        blocked = editor.blockSignals(True)

        it = QTreeWidgetItemIterator(editor)
        itm = it.value()
        while itm is not None:
            external = required_modules.get(itm._name)
            expanded = False
            if external is None:
                state = Qt.Unchecked
            elif external:
                state = Qt.Checked
                expanded = True
            else:
                state = Qt.PartiallyChecked

            itm.setCheckState(0, state)

            # Make sure every explicitly checked item is visible.
            if expanded:
                parent = itm.parent()
                while parent is not None:
                    parent.setExpanded(True)
                    parent = parent.parent()

            it += 1
            itm = it.value()

        editor.blockSignals(blocked)

        model = self._extlib_edit.model()

        # Note that we can't simply block the model's signals as this would
        # interfere with the model/view interactions.
        self._ignore_extlib_changes = True

        for extlib in external_libraries_metadata:
            if extlib.name in required_libraries:
                for idx, itm in enumerate(extlib._items):
                    itm.setFlags(
                            Qt.ItemIsEnabled|Qt.ItemIsEditable if idx != 0
                                    else Qt.ItemIsEnabled)
            else:
                for itm in extlib._items:
                    itm.setFlags(Qt.NoItemFlags)

        self._ignore_extlib_changes = False

    def _update_extlib_editor(self):
        """ Update the external library editor. """

        project = self.project
        model = self._extlib_edit.model()

        blocked = model.blockSignals(True)

        for extlib in external_libraries_metadata:
            _, defs, incp, libs = extlib._items

            for prj_extlib in project.external_libraries:
                if prj_extlib.name == extlib.name:
                    defs.setText(prj_extlib.defines)
                    incp.setText(prj_extlib.includepath)
                    libs.setText(prj_extlib.libs)
                    break
            else:
                defs.setText('')
                incp.setText('')
                libs.setText(extlib.libs)

        model.blockSignals(blocked)

    def _version_changed(self, idx):
        """ Invoked when the target Python version changes. """

        project = self.project

        project.python_target_version = get_supported_python_version(idx)
        self._update_page()

        project.modified = True

    def _ssl_changed(self, state):
        """ Invoked when the SSL support changes. """

        project = self.project

        project.python_ssl = (state == Qt.Checked)
        self._set_dependencies()

        project.modified = True

    def _platforms_changed(self, state):
        """ Invoked when the platforms change. """

        project = self._project

        project.python_use_platform = []

        for plat in self._platform_buttons:
            if plat.checkState() == Qt.Checked:
                project.python_use_platform.append(plat._scope)

        project.modified = True

    def _module_changed(self, itm, col):
        """ Invoked when a standard library module has changed. """

        project = self._project
        name = itm._name

        if name in project.standard_library:
            project.standard_library.remove(name)
        else:
            project.standard_library.append(name)

        self._set_dependencies()

        project.modified = True

    def _extlib_changed(self, itm):
        """ Invoked when an external library has changed. """

        if self._ignore_extlib_changes:
            return

        self._ignore_extlib_changes = True

        project = self.project

        idx = self._extlib_edit.model().indexFromItem(itm)
        extlib = external_libraries_metadata[idx.row()]
        col = idx.column()

        # Get the project entry, creating it if necessary.
        for prj_extlib in project.external_libraries:
            if prj_extlib.name == extlib.name:
                break
        else:
            prj_extlib = ExternalLibrary(extlib.name, '', '', extlib.libs)
            project.external_libraries.append(prj_extlib)

        # Update the project.
        text = itm.text().strip()

        if col == 1:
            prj_extlib.defines = text
        elif col == 2:
            prj_extlib.includepath = text
        elif col == 3:
            if text == '':
                text = extlib.libs
                itm.setText(text)

            prj_extlib.libs = text

        # If the project entry corresponds to the default then remove it.
        if prj_extlib.defines == '' and prj_extlib.includepath == '' and prj_extlib.libs == extlib.libs:
            project.external_libraries.remove(prj_extlib)

        project.modified = True

        self._ignore_extlib_changes = False
class IndustrialDualAnalogInV2(COMCUPluginBase):
    def __init__(self, *args):
        super().__init__(BrickletIndustrialDualAnalogInV2, *args)

        self.analog_in = self.device

        self.cbe_voltage0 = CallbackEmulator(self.analog_in.get_voltage,
                                             0,
                                             self.cb_voltage,
                                             self.increase_error_count,
                                             pass_arguments_to_result_callback=True)

        self.cbe_voltage1 = CallbackEmulator(self.analog_in.get_voltage,
                                             1,
                                             self.cb_voltage,
                                             self.increase_error_count,
                                             pass_arguments_to_result_callback=True)

        self.calibration = None

        self.sample_rate_label = QLabel('Sample Rate:')
        self.sample_rate_combo = QComboBox()
        self.sample_rate_combo.addItem('976 Hz')
        self.sample_rate_combo.addItem('488 Hz')
        self.sample_rate_combo.addItem('244 Hz')
        self.sample_rate_combo.addItem('122 Hz')
        self.sample_rate_combo.addItem('61 Hz')
        self.sample_rate_combo.addItem('4 Hz')
        self.sample_rate_combo.addItem('2 Hz')
        self.sample_rate_combo.addItem('1 Hz')

        self.current_voltage = [CurveValueWrapper(), CurveValueWrapper()] # float, V
        self.calibration_button = QPushButton('Calibration...')

        self.sample_rate_combo.currentIndexChanged.connect(self.sample_rate_combo_index_changed)
        self.calibration_button.clicked.connect(self.calibration_button_clicked)

        plots = [('Channel 0', Qt.red, self.current_voltage[0], format_voltage),
                 ('Channel 1', Qt.blue, self.current_voltage[1], format_voltage)]
        self.plot_widget = PlotWidget('Voltage [V]', plots, y_resolution=0.001)

        # Define lines
        line = QFrame()
        line.setObjectName("line")
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        line1 = QFrame()
        line1.setObjectName("line1")
        line1.setFrameShape(QFrame.HLine)
        line1.setFrameShadow(QFrame.Sunken)

        line2 = QFrame()
        line2.setObjectName("line2")
        line2.setFrameShape(QFrame.HLine)
        line2.setFrameShadow(QFrame.Sunken)

        # Define channel LED status config widgets
        self.led_config_ch0_label = QLabel('Channel 0')
        self.led_config_ch1_label = QLabel('Channel 1')
        self.led_config_label = QLabel('LED Config:')
        self.led_status_config_label = QLabel('LED Status Config:')
        self.led_status_config_ch0_min_label = QLabel('Min:')
        self.led_status_config_ch0_max_label = QLabel('Max:')
        self.led_status_config_ch1_min_label = QLabel('Min:')
        self.led_status_config_ch1_max_label = QLabel('Max:')

        self.led_config_ch0_combo = QComboBox()
        self.led_config_ch0_combo.addItem('Off')
        self.led_config_ch0_combo.addItem('On')
        self.led_config_ch0_combo.addItem('Show Heartbeat')
        self.led_config_ch0_combo.addItem('Show Channel Status')
        self.led_config_ch0_combo.currentIndexChanged.connect(self.led_config_ch0_combo_changed)

        self.led_config_ch1_combo = QComboBox()
        self.led_config_ch1_combo.addItem('Off')
        self.led_config_ch1_combo.addItem('On')
        self.led_config_ch1_combo.addItem('Show Heartbeat')
        self.led_config_ch1_combo.addItem('Show Channel Status')
        self.led_config_ch1_combo.currentIndexChanged.connect(self.led_config_ch1_combo_changed)

        self.led_status_config_ch0_combo = QComboBox()
        self.led_status_config_ch0_combo.addItem('Threshold')
        self.led_status_config_ch0_combo.addItem('Intensity')
        self.led_status_config_ch0_combo.currentIndexChanged.connect(self.led_status_config_ch0_combo_changed)

        self.led_status_config_ch1_combo = QComboBox()
        self.led_status_config_ch1_combo.addItem('Threshold')
        self.led_status_config_ch1_combo.addItem('Intensity')
        self.led_status_config_ch1_combo.currentIndexChanged.connect(self.led_status_config_ch1_combo_changed)

        self.led_status_config_ch0_min_sbox = QSpinBox()
        self.led_status_config_ch0_min_sbox.setMinimum(-35000)
        self.led_status_config_ch0_min_sbox.setMaximum(35000)
        self.led_status_config_ch0_min_sbox.setValue(0)
        self.led_status_config_ch0_min_sbox.setSingleStep(1)
        self.led_status_config_ch0_min_sbox.setSuffix(' mV')
        self.led_status_config_ch0_min_sbox.valueChanged.connect(self.led_status_config_ch0_min_sbox_changed)

        self.led_status_config_ch0_max_sbox = QSpinBox()
        self.led_status_config_ch0_max_sbox.setMinimum(-35000)
        self.led_status_config_ch0_max_sbox.setMaximum(35000)
        self.led_status_config_ch0_max_sbox.setValue(0)
        self.led_status_config_ch0_max_sbox.setSingleStep(1)
        self.led_status_config_ch0_max_sbox.setSuffix(' mV')
        self.led_status_config_ch0_max_sbox.valueChanged.connect(self.led_status_config_ch0_max_sbox_changed)

        self.led_status_config_ch1_min_sbox = QSpinBox()
        self.led_status_config_ch1_min_sbox.setMinimum(-35000)
        self.led_status_config_ch1_min_sbox.setMaximum(35000)
        self.led_status_config_ch1_min_sbox.setValue(0)
        self.led_status_config_ch1_min_sbox.setSingleStep(1)
        self.led_status_config_ch1_min_sbox.setSuffix(' mV')
        self.led_status_config_ch1_min_sbox.valueChanged.connect(self.led_status_config_ch1_min_sbox_changed)

        self.led_status_config_ch1_max_sbox = QSpinBox()
        self.led_status_config_ch1_max_sbox.setMinimum(-35000)
        self.led_status_config_ch1_max_sbox.setMaximum(35000)
        self.led_status_config_ch1_max_sbox.setValue(0)
        self.led_status_config_ch1_max_sbox.setSingleStep(1)
        self.led_status_config_ch1_max_sbox.setSuffix(' mV')
        self.led_status_config_ch1_max_sbox.valueChanged.connect(self.led_status_config_ch1_max_sbox_changed)

        # Define size policies
        h_sp = QSizePolicy()
        h_sp.setHorizontalPolicy(QSizePolicy.Expanding)

        # Set size policies
        self.sample_rate_combo.setSizePolicy(h_sp)
        self.led_config_ch0_combo.setSizePolicy(h_sp)
        self.led_config_ch1_combo.setSizePolicy(h_sp)
        self.led_status_config_ch0_combo.setSizePolicy(h_sp)
        self.led_status_config_ch1_combo.setSizePolicy(h_sp)
        self.led_status_config_ch0_min_sbox.setSizePolicy(h_sp)
        self.led_status_config_ch0_max_sbox.setSizePolicy(h_sp)
        self.led_status_config_ch1_min_sbox.setSizePolicy(h_sp)
        self.led_status_config_ch1_max_sbox.setSizePolicy(h_sp)

        # Define layouts
        hlayout = QHBoxLayout()
        vlayout = QVBoxLayout()
        glayout = QGridLayout()
        layout = QVBoxLayout(self)
        hlayout_ch0_min_max = QHBoxLayout()
        hlayout_ch1_min_max = QHBoxLayout()

        # Populate layouts
        vlayout.addWidget(self.calibration_button)
        hlayout.addWidget(self.sample_rate_label)
        hlayout.addWidget(self.sample_rate_combo)
        vlayout.addLayout(hlayout)
        vlayout.addWidget(line1)

        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_min_label)
        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_min_sbox)
        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_max_label)
        hlayout_ch0_min_max.addWidget(self.led_status_config_ch0_max_sbox)

        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_min_label)
        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_min_sbox)
        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_max_label)
        hlayout_ch1_min_max.addWidget(self.led_status_config_ch1_max_sbox)

        glayout.addWidget(self.led_config_ch0_label, 0, 1, 1, 1) # R, C, RS, CS
        glayout.addWidget(self.led_config_ch1_label, 0, 2, 1, 1)

        glayout.addWidget(line2, 1, 0, 1, 3)

        glayout.addWidget(self.led_config_label, 2, 0, 1, 1)
        glayout.addWidget(self.led_config_ch0_combo, 2, 1, 1, 1)
        glayout.addWidget(self.led_config_ch1_combo, 2, 2, 1, 1)

        glayout.addWidget(self.led_status_config_label, 3, 0, 1, 1)
        glayout.addWidget(self.led_status_config_ch0_combo, 3, 1, 1, 1)
        glayout.addWidget(self.led_status_config_ch1_combo, 3, 2, 1, 1)

        glayout.addLayout(hlayout_ch0_min_max, 4, 1, 1, 1)
        glayout.addLayout(hlayout_ch1_min_max, 4, 2, 1, 1)

        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(vlayout)
        layout.addLayout(glayout)

        self.ui_group_ch_status_ch0 = [self.led_status_config_ch0_combo,
                                       self.led_status_config_ch0_min_sbox,
                                       self.led_status_config_ch0_max_sbox]

        self.ui_group_ch_status_ch1 = [self.led_status_config_ch1_combo,
                                       self.led_status_config_ch1_min_sbox,
                                       self.led_status_config_ch1_max_sbox]

    def start(self):
        async_call(self.analog_in.get_sample_rate, None, self.get_sample_rate_async, self.increase_error_count)

        for channel in range(2):
            async_call(self.analog_in.get_channel_led_config, channel, self.get_channel_led_config_async, self.increase_error_count,
                       pass_arguments_to_result_callback=True)
            async_call(self.analog_in.get_channel_led_status_config, channel, self.get_channel_led_status_config_async, self.increase_error_count,
                       pass_arguments_to_result_callback=True)

        self.cbe_voltage0.set_period(100)
        self.cbe_voltage1.set_period(100)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_voltage0.set_period(0)
        self.cbe_voltage1.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        if self.calibration != None:
            self.calibration.close()

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletIndustrialDualAnalogInV2.DEVICE_IDENTIFIER

    def calibration_button_clicked(self):
        if self.calibration == None:
            self.calibration = Calibration(self)

        self.calibration_button.setEnabled(False)
        self.calibration.show()

    def sample_rate_combo_index_changed(self, index):
        async_call(self.analog_in.set_sample_rate, index, None, self.increase_error_count)

    def led_config_ch0_combo_changed(self, index):
        if index != self.analog_in.CHANNEL_LED_CONFIG_SHOW_CHANNEL_STATUS:
            for e in self.ui_group_ch_status_ch0:
                e.setEnabled(False)
        else:
            for e in self.ui_group_ch_status_ch0:
                e.setEnabled(True)

        self.analog_in.set_channel_led_config(0, index)

    def led_config_ch1_combo_changed(self, index):
        if index != self.analog_in.CHANNEL_LED_CONFIG_SHOW_CHANNEL_STATUS:
            for e in self.ui_group_ch_status_ch1:
                e.setEnabled(False)
        else:
            for e in self.ui_group_ch_status_ch1:
                e.setEnabled(True)

        self.analog_in.set_channel_led_config(1, index)

    def led_status_config_ch0_combo_changed(self, index):
        self.analog_in.set_channel_led_status_config(0,
                                                     self.led_status_config_ch0_min_sbox.value(),
                                                     self.led_status_config_ch0_max_sbox.value(),
                                                     index)

    def led_status_config_ch1_combo_changed(self, index):
        self.analog_in.set_channel_led_status_config(1,
                                                     self.led_status_config_ch1_min_sbox.value(),
                                                     self.led_status_config_ch1_max_sbox.value(),
                                                     index)

    def led_status_config_ch0_min_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(0,
                                                     self.led_status_config_ch0_min_sbox.value(),
                                                     self.led_status_config_ch0_max_sbox.value(),
                                                     self.led_status_config_ch0_combo.currentIndex())

    def led_status_config_ch0_max_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(0,
                                                     self.led_status_config_ch0_min_sbox.value(),
                                                     self.led_status_config_ch0_max_sbox.value(),
                                                     self.led_status_config_ch0_combo.currentIndex())

    def led_status_config_ch1_min_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(1,
                                                     self.led_status_config_ch1_min_sbox.value(),
                                                     self.led_status_config_ch1_max_sbox.value(),
                                                     self.led_status_config_ch1_combo.currentIndex())

    def led_status_config_ch1_max_sbox_changed(self, value):
        self.analog_in.set_channel_led_status_config(1,
                                                     self.led_status_config_ch1_min_sbox.value(),
                                                     self.led_status_config_ch1_max_sbox.value(),
                                                     self.led_status_config_ch1_combo.currentIndex())

    def get_voltage_value0(self):
        return self.voltage_value[0]

    def get_voltage_value1(self):
        return self.voltage_value[1]

    def get_sample_rate_async(self, rate):
        self.sample_rate_combo.blockSignals(True)

        self.sample_rate_combo.setCurrentIndex(rate)

        self.sample_rate_combo.blockSignals(False)

    def get_channel_led_config_async(self, channel, config):
        self.led_config_ch0_combo.blockSignals(True)
        self.led_config_ch1_combo.blockSignals(True)

        if channel == 0:
            self.led_config_ch0_combo.setCurrentIndex(config)
        elif channel == 1:
            self.led_config_ch1_combo.setCurrentIndex(config)

        self.led_config_ch0_combo.blockSignals(False)
        self.led_config_ch1_combo.blockSignals(False)

    def get_channel_led_status_config_async(self, channel, config):
        self.led_status_config_ch0_combo.blockSignals(True)
        self.led_status_config_ch1_combo.blockSignals(True)

        if channel == 0:
            self.led_status_config_ch0_combo.setCurrentIndex(config.config)
            self.led_status_config_ch0_max_sbox.setValue(config.max)
            self.led_status_config_ch0_min_sbox.setValue(config.min)
        elif channel == 1:
            self.led_status_config_ch1_combo.setCurrentIndex(config.config)
            self.led_status_config_ch1_max_sbox.setValue(config.max)
            self.led_status_config_ch1_min_sbox.setValue(config.min)

        self.led_status_config_ch0_combo.blockSignals(False)
        self.led_status_config_ch1_combo.blockSignals(False)

    def cb_voltage(self, sensor, voltage):
        self.current_voltage[sensor].value = voltage / 1000.0
Beispiel #18
0
class fx_selector(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.dump_dir = os.path.join(get_sim_path(), "light_dump")

        self.layout = QVBoxLayout()
        label = QLabel(_("Wavelengths") + ":")
        self.layout.addWidget(label)

        self.cb = QComboBox()
        self.layout.addWidget(self.cb)
        self.setLayout(self.layout)
        self.show()
        self.start = ""
        self.end = ""
        self.show_all = False

    def get_text(self):
        out = self.cb.currentText()
        out = out.split(" ")[0]
        return out

    def file_name_set_start(self, start):
        self.start = start

    def file_name_set_end(self, end):
        self.end = end

    def find_modes(self, path):
        result = []
        lines = []
        dump_dir = os.path.join(get_sim_path(), "light_dump")
        path = os.path.join(dump_dir, "wavelengths.dat")

        if os.path.isfile(path) == True:

            f = open(path, "r")
            lines = f.readlines()
            f.close()

            for l in range(0, len(lines)):
                txt = lines[l].rstrip()
                if txt != "":
                    result.append(txt)

        if os.path.isdir(dump_dir) == True:
            files = os.listdir(dump_dir)
            for f in files:
                if f.startswith("light_ray_"):
                    f = f[:-4]
                    f = f[10:]
                    #print(f)
                    result.append(f)

        return result

    def update(self):
        self.cb.blockSignals(True)

        thefiles = self.find_modes(self.dump_dir)
        thefiles.sort()
        if len(thefiles) == 0:
            self.setEnabled(False)
        else:
            self.setEnabled(True)

        self.cb.clear()
        if self.show_all == True:
            self.cb.addItem("all")
        for i in range(0, len(thefiles)):
            path = os.path.join(self.dump_dir,
                                self.start + str(thefiles[i]) + self.end)
            #print(path)
            if os.path.isfile(path):
                self.cb.addItem(str(thefiles[i]) + " nm")
        self.cb.setCurrentIndex(0)
        self.cb.blockSignals(False)
Beispiel #19
0
class class_optical(QWidget):

	edit_list=[]

	line_number=[]

	file_name=""
	name=""
	visible=1

	def __init__(self):
		QWidget.__init__(self)
		self.dump_dir=os.path.join(os.getcwd(),"light_dump")
		find_models()

		self.setWindowIcon(QIcon(os.path.join(get_image_file_path(),"image.png")))

		self.setMinimumSize(1000, 600)

		self.edit_list=[]
		self.line_number=[]
		self.articles=[]
		input_files=[]
		input_files.append(os.path.join(os.getcwd(),"light_dump","light_2d_photons.dat"))
		input_files.append(os.path.join(os.getcwd(),"light_dump","light_2d_photons_asb.dat"))
		input_files.append(os.path.join(os.getcwd(),"light_dump","reflect.dat"))

		plot_labels=[]
		plot_labels.append("Photon distribution")
		plot_labels.append("Photon distribution absorbed")
		plot_labels.append("Reflection")


		self.setGeometry(300, 300, 600, 600)
		self.setWindowTitle(_("Optical simulation editor (www.gpvdm.com)"))    

		self.setWindowIcon(QIcon(os.path.join(get_image_file_path(),"optics.png")))

		self.main_vbox=QVBoxLayout()

		menubar = QMenuBar()

		file_menu = menubar.addMenu('&File')
		self.menu_refresh=file_menu.addAction(_("&Refresh"))
		self.menu_refresh.triggered.connect(self.update)

		self.menu_close=file_menu.addAction(_("&Close"))
		self.menu_close.triggered.connect(self.callback_close)

		self.main_vbox.addWidget(menubar)

		toolbar=QToolBar()

		toolbar.setIconSize(QSize(48, 48))

		self.run = QAction(QIcon(os.path.join(get_image_file_path(),"play.png")), _("Run"), self)
		self.run.triggered.connect(self.callback_run)
		toolbar.addAction(self.run)


		label=QLabel(_("Wavelengths:"))
		toolbar.addWidget(label)

		self.cb = QComboBox()
		self.update_cb()
		toolbar.addWidget(self.cb)
		self.cb.currentIndexChanged.connect(self.mode_changed)

		label=QLabel(_("Optical model:"))
		toolbar.addWidget(label)

		self.cb_model = QComboBox()
		toolbar.addWidget(self.cb_model)
		self.update_cb_model()
		
		self.cb_model.activated.connect(self.on_cb_model_changed)

		label=QLabel(_("Solar spectrum:"))
		toolbar.addWidget(label)
		self.light_source_model = QComboBox()
		self.update_light_source_model()
		toolbar.addWidget(self.light_source_model)
		self.light_source_model.activated.connect(self.on_light_source_model_changed)
		
		spacer = QWidget()
		spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		toolbar.addWidget(spacer)


		self.help = QAction(QIcon(os.path.join(get_image_file_path(),"help.png")), 'Help', self)
		self.help.triggered.connect(self.callback_help)
		toolbar.addAction(self.help)

		self.main_vbox.addWidget(toolbar)


		self.progress_window=progress_class()

		self.notebook = QTabWidget()

		self.notebook.setMovable(True)


		self.fig_photon_density = band_graph()
		self.fig_photon_density.set_data_file("light_1d_photons_tot_norm.dat")
		self.fig_photon_density.init()
		self.notebook.addTab(self.fig_photon_density,"Photon density")

		self.fig_photon_abs = band_graph()
		self.fig_photon_abs.set_data_file("light_1d_photons_tot_abs_norm.dat")
		self.fig_photon_abs.init()
		self.notebook.addTab(self.fig_photon_abs,"Photon absorbed")

		widget=tab_class()
		widget.init("light.inp","Optical setup")
		self.notebook.addTab(widget,"Optical setup")


		self.plot_widgets=[]
		self.progress_window.start()
		for i in range(0,len(input_files)):
			self.plot_widgets.append(plot_widget())
			self.plot_widgets[i].init()
			self.plot_widgets[i].set_labels([plot_labels[0]])
			self.plot_widgets[i].load_data([input_files[i]],os.path.splitext(input_files[i])[0]+".oplot")

			self.plot_widgets[i].do_plot()
			#self.plot_widgets[i].show()
			self.notebook.addTab(self.plot_widgets[i],plot_labels[i])


		self.fig_photon_density.draw_graph()
		self.fig_photon_abs.draw_graph()

		self.progress_window.stop()


		self.main_vbox.addWidget(self.notebook)


		self.setLayout(self.main_vbox)

		return


	def onclick(self, event):
		for i in range(0,len(self.layer_end)):
			if (self.layer_end[i]>event.xdata):
				break
		pwd=os.getcwd()
		plot_gen([os.path.join(pwd,"materials",self.layer_name[i],"alpha.omat")],[],None,"")

	def update_cb(self):
		self.cb.blockSignals(True)
		thefiles=find_modes(self.dump_dir)
		thefiles.sort()
		files_short=thefiles[::2]
		self.cb.clear()
		self.cb.addItem("all")
		for i in range(0, len(files_short)):
			self.cb.addItem(str(files_short[i])+" nm")
		self.cb.setCurrentIndex(0)
		self.cb.blockSignals(False)

	def update_cb_model(self):
		self.cb_model.blockSignals(True)

		self.cb_model.clear()
		models=find_models()
		if len(models)==0:
			error_dlg(self,_("I can't find any optical plugins, I think the model is not installed properly."))
			return

		for i in range(0, len(models)):
			self.cb_model.addItem(models[i])

		used_model=inp_get_token_value("light.inp", "#light_model")
		print(models,used_model)
		if models.count(used_model)==0:
			used_model="exp"
			inp_update_token_value("light.inp", "#light_model","exp",1)
			self.cb_model.setCurrentIndex(self.cb_model.findText(used_model))
		else:
			self.cb_model.setCurrentIndex(self.cb_model.findText(used_model))

		scan_item_add("light.inp","#light_model","Optical model",1)

		self.cb_model.blockSignals(False)

	def update_light_source_model(self):
		self.light_source_model.blockSignals(True)
		models=find_light_source()
		for i in range(0, len(models)):
			self.light_source_model.addItem(models[i])

		used_model=inp_get_token_value("light.inp", "#sun")

		print("models================",models,used_model)
		if models.count(used_model)==0:
			used_model="sun"
			inp_update_token_value("light.inp", "#sun","sun",1)

		self.light_source_model.setCurrentIndex(self.light_source_model.findText(used_model))
		scan_item_add("light.inp","#sun","Light source",1)
		self.light_source_model.blockSignals(False)

	def callback_close(self):
		self.hide()
		return True


	def update(self):
		self.fig_photon_density.my_figure.clf()
		self.fig_photon_density.draw_graph()
		self.fig_photon_density.canvas.draw()

		self.fig_photon_abs.my_figure.clf()
		self.fig_photon_abs.draw_graph()
		self.fig_photon_abs.canvas.draw()

		for i in range(0,len(self.plot_widgets)):
			self.plot_widgets[i].update()


	def callback_run(self):
		dump_optics=inp_get_token_value("dump.inp", "#dump_optics")
		dump_optics_verbose=inp_get_token_value("dump.inp", "#dump_optics_verbose")

		inp_update_token_value("dump.inp", "#dump_optics","true",1)
		inp_update_token_value("dump.inp", "#dump_optics_verbose","true",1)
		cmd = get_exe_command()+' --simmode opticalmodel@optics'
		print(cmd)
		ret= os.system(cmd)

		inp_update_token_value("dump.inp", "#dump_optics",dump_optics,1)
		inp_update_token_value("dump.inp", "#dump_optics_verbose",dump_optics_verbose,1)
		
		self.update()
		self.update_cb()

		inp_update_token_value("dump.inp", "#dump_optics","true",1)
		inp_update_token_value("dump.inp", "#dump_optics_verbose","true",1)
		

	def mode_changed(self):
		cb_text=self.cb.currentText()

		if cb_text=="all":
			self.fig_photon_density.set_data_file("light_1d_photons_tot_norm.dat")
			self.fig_photon_abs.set_data_file("light_1d_photons_tot_abs_norm.dat")
		else:
			self.fig_photon_density.set_data_file("light_1d_"+cb_text[:-3]+"_photons_norm.dat")
			self.fig_photon_abs.set_data_file("light_1d_"+cb_text[:-3]+"_photons_abs.dat")

		self.update()

	def on_cb_model_changed(self):
		cb_text=self.cb_model.currentText()
		inp_update_token_value("light.inp", "#light_model", cb_text,1)


	def on_light_source_model_changed(self):
		cb_text=self.light_source_model.currentText()
		cb_text=cb_text
		inp_update_token_value("light.inp", "#sun", cb_text,1)

	def callback_help(self, widget, data=None):
		webbrowser.open('http://www.gpvdm.com/man/index.html')
Beispiel #20
0
class Thermocouple(PluginBase):
    qtcb_error_state = pyqtSignal(bool, bool)

    def __init__(self, *args):
        super().__init__(BrickletThermocouple, *args)

        self.thermo = self.device

        self.qtcb_error_state.connect(self.cb_error_state)
        self.thermo.register_callback(self.thermo.CALLBACK_ERROR_STATE,
                                      self.qtcb_error_state.emit)

        self.cbe_temperature = CallbackEmulator(self.thermo.get_temperature,
                                                None,
                                                self.cb_temperature,
                                                self.increase_error_count)

        self.current_temperature = CurveValueWrapper() # float, °C

        self.error_label = QLabel('Current Errors: None')
        self.error_label.setAlignment(Qt.AlignVCenter | Qt.AlignRight)

        plots = [('Temperature', Qt.red, self.current_temperature, '{:.2f} °C'.format)]
        self.plot_widget = PlotWidget('Temperature [°C]', plots, extra_key_widgets=[self.error_label], y_resolution=0.01)

        self.averaging_label = QLabel('Averaging:')
        self.averaging_combo = QComboBox()
        self.averaging_combo.addItem('1', BrickletThermocouple.AVERAGING_1)
        self.averaging_combo.addItem('2', BrickletThermocouple.AVERAGING_2)
        self.averaging_combo.addItem('4', BrickletThermocouple.AVERAGING_4)
        self.averaging_combo.addItem('8', BrickletThermocouple.AVERAGING_8)
        self.averaging_combo.addItem('16', BrickletThermocouple.AVERAGING_16)

        self.type_label = QLabel('Thermocouple Type:')
        self.type_combo = QComboBox()
        self.type_combo.addItem('B', BrickletThermocouple.TYPE_B)
        self.type_combo.addItem('E', BrickletThermocouple.TYPE_E)
        self.type_combo.addItem('J', BrickletThermocouple.TYPE_J)
        self.type_combo.addItem('K', BrickletThermocouple.TYPE_K)
        self.type_combo.addItem('N', BrickletThermocouple.TYPE_N)
        self.type_combo.addItem('R', BrickletThermocouple.TYPE_R)
        self.type_combo.addItem('S', BrickletThermocouple.TYPE_S)
        self.type_combo.addItem('T', BrickletThermocouple.TYPE_T)
        self.type_combo.addItem('Gain 8', BrickletThermocouple.TYPE_G8)
        self.type_combo.addItem('Gain 32', BrickletThermocouple.TYPE_G32)

        self.filter_label = QLabel('Noise Rejection Filter:')
        self.filter_combo = QComboBox()
        self.filter_combo.addItem('50 Hz', BrickletThermocouple.FILTER_OPTION_50HZ)
        self.filter_combo.addItem('60 Hz', BrickletThermocouple.FILTER_OPTION_60HZ)

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.averaging_label)
        hlayout.addWidget(self.averaging_combo)
        hlayout.addStretch()
        hlayout.addWidget(self.type_label)
        hlayout.addWidget(self.type_combo)
        hlayout.addStretch()
        hlayout.addWidget(self.filter_label)
        hlayout.addWidget(self.filter_combo)

        line = QFrame()
        line.setObjectName("line")
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(hlayout)

        self.averaging_combo.currentIndexChanged.connect(self.configuration_changed)
        self.type_combo.currentIndexChanged.connect(self.configuration_changed)
        self.filter_combo.currentIndexChanged.connect(self.configuration_changed)

    def start(self):
        async_call(self.thermo.get_configuration, None, self.get_configuration_async, self.increase_error_count)
        async_call(self.thermo.get_error_state, None, self.cb_error_state, self.increase_error_count,
                   expand_result_tuple_for_callback=True)

        self.cbe_temperature.set_period(100)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_temperature.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletThermocouple.DEVICE_IDENTIFIER

    def configuration_changed(self, _):
        conf_averaging = self.averaging_combo.itemData(self.averaging_combo.currentIndex())
        conf_type = self.type_combo.itemData(self.type_combo.currentIndex())
        conf_filter = self.filter_combo.itemData(self.filter_combo.currentIndex())

        self.thermo.set_configuration(conf_averaging, conf_type, conf_filter)

    def cb_temperature(self, temperature):
        self.current_temperature.value = temperature / 100.0

    def get_configuration_async(self, conf):
        self.averaging_combo.blockSignals(True)
        self.averaging_combo.setCurrentIndex(self.averaging_combo.findData(conf.averaging))
        self.averaging_combo.blockSignals(False)

        self.type_combo.blockSignals(True)
        self.type_combo.setCurrentIndex(self.type_combo.findData(conf.thermocouple_type))
        self.type_combo.blockSignals(False)

        self.filter_combo.blockSignals(True)
        self.filter_combo.setCurrentIndex(self.filter_combo.findData(conf.filter))
        self.filter_combo.blockSignals(False)

    def cb_error_state(self, over_under, open_circuit):
        if over_under or open_circuit:
            text = 'Current Errors: '

            if over_under:
                text += 'Over/Under Voltage'

            if over_under and open_circuit:
                text += ' and '

            if open_circuit:
                text += 'Open Circuit\n(defective thermocouple or nothing connected)'

            self.error_label.setStyleSheet('QLabel { color : red }')
            self.error_label.setText(text)
        else:
            self.error_label.setStyleSheet('')
            self.error_label.setText('Current Errors: None')
Beispiel #21
0
class LedgerAuthDialog(QDialog):
    def __init__(self, handler, data):
        '''Ask user for 2nd factor authentication. Support text, security card and paired mobile methods.
        Use last method from settings, but support new pairing and downgrade.
        '''
        QDialog.__init__(self, handler.top_level_window())
        self.handler = handler
        self.txdata = data
        self.idxs = self.txdata['keycardData'] if self.txdata['confirmationType'] > 1 else ''
        self.setMinimumWidth(650)
        self.setWindowTitle(_("Ledger Wallet Authentication"))
        self.cfg = copy.deepcopy(self.handler.win.wallet.get_keystore().cfg)
        self.dongle = self.handler.win.wallet.get_keystore().get_client().dongle
        self.ws = None
        self.pin = ''
        
        self.devmode = self.getDevice2FAMode()
        if self.devmode == 0x11 or self.txdata['confirmationType'] == 1:
            self.cfg['mode'] = 0
        
        vbox = QVBoxLayout()
        self.setLayout(vbox)
        
        def on_change_mode(idx):
            if idx < 2 and self.ws:
                self.ws.stop()
                self.ws = None
            self.cfg['mode'] = 0 if self.devmode == 0x11 else idx if idx > 0 else 1
            if self.cfg['mode'] > 1 and self.cfg['pair'] and not self.ws:
                self.req_validation()
            if self.cfg['mode'] > 0:
                self.handler.win.wallet.get_keystore().cfg = self.cfg
                self.handler.win.wallet.save_keystore()
            self.update_dlg()
        def add_pairing():
            self.do_pairing()
        def return_pin():
            self.pin = self.pintxt.text() if self.txdata['confirmationType'] == 1 else self.cardtxt.text() 
            if self.cfg['mode'] == 1:
                self.pin = ''.join(chr(int(str(i),16)) for i in self.pin)
            self.accept()
        
        self.modebox = QWidget()
        modelayout = QHBoxLayout()
        self.modebox.setLayout(modelayout)
        modelayout.addWidget(QLabel(_("Method:")))
        self.modes = QComboBox()
        modelayout.addWidget(self.modes, 2)
        self.addPair = QPushButton(_("Pair"))
        self.addPair.setMaximumWidth(60)
        modelayout.addWidget(self.addPair)
        modelayout.addStretch(1)
        self.modebox.setMaximumHeight(50)
        vbox.addWidget(self.modebox)
        
        self.populate_modes()
        self.modes.currentIndexChanged.connect(on_change_mode)
        self.addPair.clicked.connect(add_pairing)
        
        self.helpmsg = QTextEdit()
        self.helpmsg.setStyleSheet("QTextEdit { background-color: lightgray; }")
        self.helpmsg.setReadOnly(True)
        vbox.addWidget(self.helpmsg)
        
        self.pinbox = QWidget()
        pinlayout = QHBoxLayout()
        self.pinbox.setLayout(pinlayout)
        self.pintxt = QLineEdit()
        self.pintxt.setEchoMode(2)
        self.pintxt.setMaxLength(4)
        self.pintxt.returnPressed.connect(return_pin)
        pinlayout.addWidget(QLabel(_("Enter PIN:")))
        pinlayout.addWidget(self.pintxt)
        pinlayout.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        pinlayout.addStretch(1)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        vbox.addWidget(self.pinbox)
                    
        self.cardbox = QWidget()
        card = QVBoxLayout()
        self.cardbox.setLayout(card)
        self.addrtext = QTextEdit()
        self.addrtext.setStyleSheet("QTextEdit { color:blue; background-color:lightgray; padding:15px 10px; border:none; font-size:20pt; font-family:monospace; }")
        self.addrtext.setReadOnly(True)
        self.addrtext.setMaximumHeight(130)
        card.addWidget(self.addrtext)
        
        def pin_changed(s):
            if len(s) < len(self.idxs):
                i = self.idxs[len(s)]
                addr = self.txdata['address']
                if not constants.net.TESTNET:
                    text = addr[:i] + '<u><b>' + addr[i:i+1] + '</u></b>' + addr[i+1:]
                else:
                    # pin needs to be created from mainnet address
                    addr_mainnet = bitcoin.script_to_address(bitcoin.address_to_script(addr), net=constants.BitcoinMainnet)
                    addr_mainnet = addr_mainnet[:i] + '<u><b>' + addr_mainnet[i:i+1] + '</u></b>' + addr_mainnet[i+1:]
                    text = str(addr) + '\n' + str(addr_mainnet)
                self.addrtext.setHtml(str(text))
            else:
                self.addrtext.setHtml(_("Press Enter"))
                
        pin_changed('')    
        cardpin = QHBoxLayout()
        cardpin.addWidget(QLabel(_("Enter PIN:")))
        self.cardtxt = QLineEdit()
        self.cardtxt.setEchoMode(2)
        self.cardtxt.setMaxLength(len(self.idxs))
        self.cardtxt.textChanged.connect(pin_changed)
        self.cardtxt.returnPressed.connect(return_pin)
        cardpin.addWidget(self.cardtxt)
        cardpin.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        cardpin.addStretch(1)
        card.addLayout(cardpin)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        vbox.addWidget(self.cardbox)
        
        self.pairbox = QWidget()
        pairlayout = QVBoxLayout()
        self.pairbox.setLayout(pairlayout)
        pairhelp = QTextEdit(helpTxt[5])
        pairhelp.setStyleSheet("QTextEdit { background-color: lightgray; }")
        pairhelp.setReadOnly(True)
        pairlayout.addWidget(pairhelp, 1)
        self.pairqr = QRCodeWidget()
        pairlayout.addWidget(self.pairqr, 4)
        self.pairbox.setVisible(False)
        vbox.addWidget(self.pairbox)
        self.update_dlg()
        
        if self.cfg['mode'] > 1 and not self.ws:
            self.req_validation()
        
    def populate_modes(self):
        self.modes.blockSignals(True)
        self.modes.clear()
        self.modes.addItem(_("Summary Text PIN (requires dongle replugging)") if self.txdata['confirmationType'] == 1 else _("Summary Text PIN is Disabled"))
        if self.txdata['confirmationType'] > 1:
            self.modes.addItem(_("Security Card Challenge"))
            if not self.cfg['pair']:
                self.modes.addItem(_("Mobile - Not paired")) 
            else:
                self.modes.addItem(_("Mobile - {}").format(self.cfg['pair'][1]))
        self.modes.blockSignals(False)
        
    def update_dlg(self):
        self.modes.setCurrentIndex(self.cfg['mode'])
        self.modebox.setVisible(True)
        self.addPair.setText(_("Pair") if not self.cfg['pair'] else _("Re-Pair"))
        self.addPair.setVisible(self.txdata['confirmationType'] > 2)
        self.helpmsg.setText(helpTxt[self.cfg['mode'] if self.cfg['mode'] < 2 else 2 if self.cfg['pair'] else 4])
        self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] == 1 else 100)
        self.pairbox.setVisible(False)
        self.helpmsg.setVisible(True)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        self.pintxt.setFocus(True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True)
        self.setMaximumHeight(400)

    def do_pairing(self):
        rng = os.urandom(16)
        pairID = (hexlify(rng) + hexlify(hashlib.sha256(rng).digest()[0:1])).decode('utf-8')
        self.pairqr.setData(pairID)
        self.modebox.setVisible(False)
        self.helpmsg.setVisible(False)
        self.pinbox.setVisible(False)
        self.cardbox.setVisible(False)
        self.pairbox.setVisible(True)
        self.pairqr.setMinimumSize(300,300)
        if self.ws:
            self.ws.stop()
        self.ws = LedgerWebSocket(self, pairID)
        self.ws.pairing_done.connect(self.pairing_done)
        self.ws.start() 
               
    def pairing_done(self, data):
        if data is not None:
            self.cfg['pair'] = [ data['pairid'], data['name'], data['platform'] ]
            self.cfg['mode'] = 2
            self.handler.win.wallet.get_keystore().cfg = self.cfg
            self.handler.win.wallet.save_keystore()
        self.pin = 'paired'
        self.accept()
    
    def req_validation(self):
        if self.cfg['pair'] and 'secureScreenData' in self.txdata:
            if self.ws:
                self.ws.stop()
            self.ws = LedgerWebSocket(self, self.cfg['pair'][0], self.txdata)
            self.ws.req_updated.connect(self.req_updated)
            self.ws.start()
              
    def req_updated(self, pin):
        if pin == 'accepted':
            self.helpmsg.setText(helpTxt[3])
        else:
            self.pin = str(pin)
            self.accept()
        
    def getDevice2FAMode(self):
        apdu = [0xe0, 0x24, 0x01, 0x00, 0x00, 0x01] # get 2fa mode
        try:
            mode = self.dongle.exchange( bytearray(apdu) )
            return mode
        except BTChipException as e:
            debug_msg('Device getMode Failed')
        return 0x11
    
    def closeEvent(self, evnt):
        debug_msg("CLOSE - Stop WS")
        if self.ws:
            self.ws.stop()
        if self.pairbox.isVisible():
            evnt.ignore()
            self.update_dlg()
Beispiel #22
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        centralWidget = QWidget()

        fontLabel = QLabel("Font:")
        self.fontCombo = QFontComboBox()
        sizeLabel = QLabel("Size:")
        self.sizeCombo = QComboBox()
        styleLabel = QLabel("Style:")
        self.styleCombo = QComboBox()
        fontMergingLabel = QLabel("Automatic Font Merging:")
        self.fontMerging = QCheckBox()
        self.fontMerging.setChecked(True)

        self.scrollArea = QScrollArea()
        self.characterWidget = CharacterWidget()
        self.scrollArea.setWidget(self.characterWidget)

        self.findStyles(self.fontCombo.currentFont())
        self.findSizes(self.fontCombo.currentFont())

        self.lineEdit = QLineEdit()
        clipboardButton = QPushButton("&To clipboard")

        self.clipboard = QApplication.clipboard()

        self.fontCombo.currentFontChanged.connect(self.findStyles)
        self.fontCombo.activated[str].connect(self.characterWidget.updateFont)
        self.styleCombo.activated[str].connect(
            self.characterWidget.updateStyle)
        self.sizeCombo.currentIndexChanged[str].connect(
            self.characterWidget.updateSize)
        self.characterWidget.characterSelected.connect(self.insertCharacter)
        clipboardButton.clicked.connect(self.updateClipboard)

        controlsLayout = QHBoxLayout()
        controlsLayout.addWidget(fontLabel)
        controlsLayout.addWidget(self.fontCombo, 1)
        controlsLayout.addWidget(sizeLabel)
        controlsLayout.addWidget(self.sizeCombo, 1)
        controlsLayout.addWidget(styleLabel)
        controlsLayout.addWidget(self.styleCombo, 1)
        controlsLayout.addWidget(fontMergingLabel)
        controlsLayout.addWidget(self.fontMerging, 1)
        controlsLayout.addStretch(1)

        lineLayout = QHBoxLayout()
        lineLayout.addWidget(self.lineEdit, 1)
        lineLayout.addSpacing(12)
        lineLayout.addWidget(clipboardButton)

        centralLayout = QVBoxLayout()
        centralLayout.addLayout(controlsLayout)
        centralLayout.addWidget(self.scrollArea, 1)
        centralLayout.addSpacing(4)
        centralLayout.addLayout(lineLayout)
        centralWidget.setLayout(centralLayout)

        self.setCentralWidget(centralWidget)
        self.setWindowTitle("Character Map")

    def findStyles(self, font):
        fontDatabase = QFontDatabase()
        currentItem = self.styleCombo.currentText()
        self.styleCombo.clear()

        for style in fontDatabase.styles(font.family()):
            self.styleCombo.addItem(style)

        styleIndex = self.styleCombo.findText(currentItem)
        if styleIndex == -1:
            self.styleCombo.setCurrentIndex(0)
        else:
            self.styleCombo.setCurrentIndex(styleIndex)

    def findSizes(self, font):
        fontDatabase = QFontDatabase()
        currentSize = self.sizeCombo.currentText()
        self.sizeCombo.blockSignals(True)
        self.sizeCombo.clear()

        if fontDatabase.isSmoothlyScalable(font.family(),
                                           fontDatabase.styleString(font)):
            for size in QFontDatabase.standardSizes():
                self.sizeCombo.addItem(str(size))
                self.sizeCombo.setEditable(True)
        else:
            for size in fontDatabase.smoothSizes(
                    font.family(), fontDatabase.styleString(font)):
                self.sizeCombo.addItem(str(size))
                self.sizeCombo.setEditable(False)

        self.sizeCombo.blockSignals(False)

        sizeIndex = self.sizeCombo.findText(currentSize)
        if sizeIndex == -1:
            self.sizeCombo.setCurrentIndex(max(0, self.sizeCombo.count() / 3))
        else:
            self.sizeCombo.setCurrentIndex(sizeIndex)

    def insertCharacter(self, character):
        self.lineEdit.insert(character)

    def updateClipboard(self):
        self.clipboard.setText(self.lineEdit.text(), QClipboard.Clipboard)
        self.clipboard.setText(self.lineEdit.text(), QClipboard.Selection)
Beispiel #23
0
class DebugViewer(QWidget):
    """
    Class implementing a widget conatining various debug related views.
    
    The individual tabs contain the interpreter shell (optional),
    the filesystem browser (optional), the two variables viewers
    (global and local), a breakpoint viewer, a watch expression viewer and
    the exception logger. Additionally a list of all threads is shown.
    
    @signal sourceFile(string, int) emitted to open a source file at a line
    """
    sourceFile = pyqtSignal(str, int)
    
    def __init__(self, debugServer, docked, vm, parent=None,
                 embeddedShell=True, embeddedBrowser=True):
        """
        Constructor
        
        @param debugServer reference to the debug server object
        @param docked flag indicating a dock window
        @param vm reference to the viewmanager object
        @param parent parent widget (QWidget)
        @param embeddedShell flag indicating whether the shell should be
            included. This flag is set to False by those layouts, that have
            the interpreter shell in a separate window.
        @param embeddedBrowser flag indicating whether the file browser should
            be included. This flag is set to False by those layouts, that
            have the file browser in a separate window or embedded
            in the project browser instead.
        """
        super(DebugViewer, self).__init__(parent)
        
        self.debugServer = debugServer
        self.debugUI = None
        
        self.setWindowIcon(UI.PixmapCache.getIcon("eric.png"))
        
        self.__mainLayout = QVBoxLayout()
        self.__mainLayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.__mainLayout)
        
        self.__tabWidget = E5TabWidget()
        self.__mainLayout.addWidget(self.__tabWidget)
        
        self.embeddedShell = embeddedShell
        if embeddedShell:
            from QScintilla.Shell import ShellAssembly
            # add the interpreter shell
            self.shellAssembly = ShellAssembly(debugServer, vm, False)
            self.shell = self.shellAssembly.shell()
            index = self.__tabWidget.addTab(
                self.shellAssembly,
                UI.PixmapCache.getIcon("shell.png"), '')
            self.__tabWidget.setTabToolTip(index, self.shell.windowTitle())
        
        self.embeddedBrowser = embeddedBrowser
        if embeddedBrowser:
            from UI.Browser import Browser
            # add the browser
            self.browser = Browser()
            index = self.__tabWidget.addTab(
                self.browser,
                UI.PixmapCache.getIcon("browser.png"), '')
            self.__tabWidget.setTabToolTip(index, self.browser.windowTitle())
        
        from .VariablesViewer import VariablesViewer
        # add the global variables viewer
        self.glvWidget = QWidget()
        self.glvWidgetVLayout = QVBoxLayout(self.glvWidget)
        self.glvWidgetVLayout.setContentsMargins(0, 0, 0, 0)
        self.glvWidgetVLayout.setSpacing(3)
        self.glvWidget.setLayout(self.glvWidgetVLayout)
        
        self.globalsViewer = VariablesViewer(self.glvWidget, True)
        self.glvWidgetVLayout.addWidget(self.globalsViewer)
        
        self.glvWidgetHLayout = QHBoxLayout()
        self.glvWidgetHLayout.setContentsMargins(3, 3, 3, 3)
        
        self.globalsFilterEdit = QLineEdit(self.glvWidget)
        self.globalsFilterEdit.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.glvWidgetHLayout.addWidget(self.globalsFilterEdit)
        self.globalsFilterEdit.setToolTip(
            self.tr("Enter regular expression patterns separated by ';'"
                    " to define variable filters. "))
        self.globalsFilterEdit.setWhatsThis(
            self.tr("Enter regular expression patterns separated by ';'"
                    " to define variable filters. All variables and"
                    " class attributes matched by one of the expressions"
                    " are not shown in the list above."))
        
        self.setGlobalsFilterButton = QPushButton(
            self.tr('Set'), self.glvWidget)
        self.glvWidgetHLayout.addWidget(self.setGlobalsFilterButton)
        self.glvWidgetVLayout.addLayout(self.glvWidgetHLayout)
        
        index = self.__tabWidget.addTab(
            self.glvWidget,
            UI.PixmapCache.getIcon("globalVariables.png"), '')
        self.__tabWidget.setTabToolTip(index, self.globalsViewer.windowTitle())
        
        self.setGlobalsFilterButton.clicked.connect(
            self.__setGlobalsFilter)
        self.globalsFilterEdit.returnPressed.connect(self.__setGlobalsFilter)
        
        # add the local variables viewer
        self.lvWidget = QWidget()
        self.lvWidgetVLayout = QVBoxLayout(self.lvWidget)
        self.lvWidgetVLayout.setContentsMargins(0, 0, 0, 0)
        self.lvWidgetVLayout.setSpacing(3)
        self.lvWidget.setLayout(self.lvWidgetVLayout)
        
        self.lvWidgetHLayout1 = QHBoxLayout()
        self.lvWidgetHLayout1.setContentsMargins(3, 3, 3, 3)
        
        self.stackComboBox = QComboBox(self.lvWidget)
        self.stackComboBox.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.lvWidgetHLayout1.addWidget(self.stackComboBox)

        self.sourceButton = QPushButton(self.tr('Source'), self.lvWidget)
        self.lvWidgetHLayout1.addWidget(self.sourceButton)
        self.sourceButton.setEnabled(False)
        self.lvWidgetVLayout.addLayout(self.lvWidgetHLayout1)

        self.localsViewer = VariablesViewer(self.lvWidget, False)
        self.lvWidgetVLayout.addWidget(self.localsViewer)
        
        self.lvWidgetHLayout2 = QHBoxLayout()
        self.lvWidgetHLayout2.setContentsMargins(3, 3, 3, 3)
        
        self.localsFilterEdit = QLineEdit(self.lvWidget)
        self.localsFilterEdit.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.lvWidgetHLayout2.addWidget(self.localsFilterEdit)
        self.localsFilterEdit.setToolTip(
            self.tr(
                "Enter regular expression patterns separated by ';' to define "
                "variable filters. "))
        self.localsFilterEdit.setWhatsThis(
            self.tr(
                "Enter regular expression patterns separated by ';' to define "
                "variable filters. All variables and class attributes matched"
                " by one of the expressions are not shown in the list above."))
        
        self.setLocalsFilterButton = QPushButton(
            self.tr('Set'), self.lvWidget)
        self.lvWidgetHLayout2.addWidget(self.setLocalsFilterButton)
        self.lvWidgetVLayout.addLayout(self.lvWidgetHLayout2)
        
        index = self.__tabWidget.addTab(
            self.lvWidget,
            UI.PixmapCache.getIcon("localVariables.png"), '')
        self.__tabWidget.setTabToolTip(index, self.localsViewer.windowTitle())
        
        self.sourceButton.clicked.connect(self.__showSource)
        self.stackComboBox.currentIndexChanged[int].connect(
            self.__frameSelected)
        self.setLocalsFilterButton.clicked.connect(self.__setLocalsFilter)
        self.localsFilterEdit.returnPressed.connect(self.__setLocalsFilter)
        
        from .CallStackViewer import CallStackViewer
        # add the call stack viewer
        self.callStackViewer = CallStackViewer(self.debugServer)
        index = self.__tabWidget.addTab(
            self.callStackViewer,
            UI.PixmapCache.getIcon("step.png"), "")
        self.__tabWidget.setTabToolTip(
            index, self.callStackViewer.windowTitle())
        self.callStackViewer.sourceFile.connect(self.sourceFile)
        self.callStackViewer.frameSelected.connect(
            self.__callStackFrameSelected)
        
        from .CallTraceViewer import CallTraceViewer
        # add the call trace viewer
        self.callTraceViewer = CallTraceViewer(self.debugServer)
        index = self.__tabWidget.addTab(
            self.callTraceViewer,
            UI.PixmapCache.getIcon("callTrace.png"), "")
        self.__tabWidget.setTabToolTip(
            index, self.callTraceViewer.windowTitle())
        self.callTraceViewer.sourceFile.connect(self.sourceFile)
        
        from .BreakPointViewer import BreakPointViewer
        # add the breakpoint viewer
        self.breakpointViewer = BreakPointViewer()
        self.breakpointViewer.setModel(self.debugServer.getBreakPointModel())
        index = self.__tabWidget.addTab(
            self.breakpointViewer,
            UI.PixmapCache.getIcon("breakpoints.png"), '')
        self.__tabWidget.setTabToolTip(
            index, self.breakpointViewer.windowTitle())
        self.breakpointViewer.sourceFile.connect(self.sourceFile)
        
        from .WatchPointViewer import WatchPointViewer
        # add the watch expression viewer
        self.watchpointViewer = WatchPointViewer()
        self.watchpointViewer.setModel(self.debugServer.getWatchPointModel())
        index = self.__tabWidget.addTab(
            self.watchpointViewer,
            UI.PixmapCache.getIcon("watchpoints.png"), '')
        self.__tabWidget.setTabToolTip(
            index, self.watchpointViewer.windowTitle())
        
        from .ExceptionLogger import ExceptionLogger
        # add the exception logger
        self.exceptionLogger = ExceptionLogger()
        index = self.__tabWidget.addTab(
            self.exceptionLogger,
            UI.PixmapCache.getIcon("exceptions.png"), '')
        self.__tabWidget.setTabToolTip(
            index, self.exceptionLogger.windowTitle())
        
        if self.embeddedShell:
            self.__tabWidget.setCurrentWidget(self.shellAssembly)
        else:
            if self.embeddedBrowser:
                self.__tabWidget.setCurrentWidget(self.browser)
            else:
                self.__tabWidget.setCurrentWidget(self.glvWidget)
        
        # add the threads viewer
        self.__mainLayout.addWidget(QLabel(self.tr("Threads:")))
        self.__threadList = QTreeWidget()
        self.__threadList.setHeaderLabels(
            [self.tr("ID"), self.tr("Name"),
             self.tr("State"), ""])
        self.__threadList.setSortingEnabled(True)
        self.__mainLayout.addWidget(self.__threadList)
        
        self.__doThreadListUpdate = True
        
        self.__threadList.currentItemChanged.connect(self.__threadSelected)
        
        self.__mainLayout.setStretchFactor(self.__tabWidget, 5)
        self.__mainLayout.setStretchFactor(self.__threadList, 1)
        
        self.currPage = None
        self.currentStack = None
        self.framenr = 0
        
        self.debugServer.clientStack.connect(self.handleClientStack)
        
        self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode")
        self.sourceButton.setVisible(not self.__autoViewSource)
        
    def preferencesChanged(self):
        """
        Public slot to handle the preferencesChanged signal.
        """
        self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode")
        self.sourceButton.setVisible(not self.__autoViewSource)
        
    def setDebugger(self, debugUI):
        """
        Public method to set a reference to the Debug UI.
        
        @param debugUI reference to the DebugUI object (DebugUI)
        """
        self.debugUI = debugUI
        self.debugUI.clientStack.connect(self.handleClientStack)
        self.callStackViewer.setDebugger(debugUI)
        
    def handleResetUI(self):
        """
        Public method to reset the SBVviewer.
        """
        self.globalsViewer.handleResetUI()
        self.localsViewer.handleResetUI()
        self.__setGlobalsFilter()
        self.__setLocalsFilter()
        self.sourceButton.setEnabled(False)
        self.currentStack = None
        self.stackComboBox.clear()
        self.__threadList.clear()
        if self.embeddedShell:
            self.__tabWidget.setCurrentWidget(self.shellAssembly)
        else:
            if self.embeddedBrowser:
                self.__tabWidget.setCurrentWidget(self.browser)
            else:
                self.__tabWidget.setCurrentWidget(self.glvWidget)
        self.breakpointViewer.handleResetUI()
        
    def handleRawInput(self):
        """
        Public slot to handle the switch to the shell in raw input mode.
        """
        if self.embeddedShell:
            self.saveCurrentPage()
            self.__tabWidget.setCurrentWidget(self.shellAssembly)
        
    def initCallStackViewer(self, projectMode):
        """
        Public method to initialize the call stack viewer.
        
        @param projectMode flag indicating to enable the project mode (boolean)
        """
        self.callStackViewer.clear()
        self.callStackViewer.setProjectMode(projectMode)
        
    def isCallTraceEnabled(self):
        """
        Public method to get the state of the call trace function.
        
        @return flag indicating the state of the call trace function (boolean)
        """
        return self.callTraceViewer.isCallTraceEnabled()
        
    def clearCallTrace(self):
        """
        Public method to clear the recorded call trace.
        """
        self.callTraceViewer.clear()
        
    def setCallTraceToProjectMode(self, enabled):
        """
        Public slot to set the call trace viewer to project mode.
        
        In project mode the call trace info is shown with project relative
        path names.
        
        @param enabled flag indicating to enable the project mode (boolean)
        """
        self.callTraceViewer.setProjectMode(enabled)
        
    def showVariables(self, vlist, globals):
        """
        Public method to show the variables in the respective window.
        
        @param vlist list of variables to display
        @param globals flag indicating global/local state
        """
        if globals:
            self.globalsViewer.showVariables(vlist, self.framenr)
        else:
            self.localsViewer.showVariables(vlist, self.framenr)
            
    def showVariable(self, vlist, globals):
        """
        Public method to show the variables in the respective window.
        
        @param vlist list of variables to display
        @param globals flag indicating global/local state
        """
        if globals:
            self.globalsViewer.showVariable(vlist)
        else:
            self.localsViewer.showVariable(vlist)
            
    def showVariablesTab(self, globals):
        """
        Public method to make a variables tab visible.
        
        @param globals flag indicating global/local state
        """
        if globals:
            self.__tabWidget.setCurrentWidget(self.glvWidget)
        else:
            self.__tabWidget.setCurrentWidget(self.lvWidget)
        
    def saveCurrentPage(self):
        """
        Public slot to save the current page.
        """
        self.currPage = self.__tabWidget.currentWidget()
        
    def restoreCurrentPage(self):
        """
        Public slot to restore the previously saved page.
        """
        if self.currPage is not None:
            self.__tabWidget.setCurrentWidget(self.currPage)
            
    def handleClientStack(self, stack):
        """
        Public slot to show the call stack of the program being debugged.
        
        @param stack list of tuples with call stack data (file name,
            line number, function name, formatted argument/values list)
        """
        block = self.stackComboBox.blockSignals(True)
        self.framenr = 0
        self.stackComboBox.clear()
        self.currentStack = stack
        self.sourceButton.setEnabled(len(stack) > 0)
        for s in stack:
            # just show base filename to make it readable
            s = (os.path.basename(s[0]), s[1], s[2])
            self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s))
        self.stackComboBox.blockSignals(block)
        
    def setVariablesFilter(self, globalsFilter, localsFilter):
        """
        Public slot to set the local variables filter.
        
        @param globalsFilter filter list for global variable types
            (list of int)
        @param localsFilter filter list for local variable types (list of int)
        """
        self.globalsFilter = globalsFilter
        self.localsFilter = localsFilter
        
    def __showSource(self):
        """
        Private slot to handle the source button press to show the selected
        file.
        """
        index = self.stackComboBox.currentIndex()
        if index > -1 and self.currentStack:
            s = self.currentStack[index]
            self.sourceFile.emit(s[0], int(s[1]))
        
    def __frameSelected(self, frmnr):
        """
        Private slot to handle the selection of a new stack frame number.
        
        @param frmnr frame number (0 is the current frame) (int)
        """
        self.framenr = frmnr
        self.debugServer.remoteClientVariables(0, self.localsFilter, frmnr)
        
        if self.__autoViewSource:
            self.__showSource()
        
    def __setGlobalsFilter(self):
        """
        Private slot to set the global variable filter.
        """
        filter = self.globalsFilterEdit.text()
        self.debugServer.remoteClientSetFilter(1, filter)
        self.debugServer.remoteClientVariables(2, self.globalsFilter)
        
    def __setLocalsFilter(self):
        """
        Private slot to set the local variable filter.
        """
        filter = self.localsFilterEdit.text()
        self.debugServer.remoteClientSetFilter(0, filter)
        if self.currentStack:
            self.debugServer.remoteClientVariables(
                0, self.localsFilter, self.framenr)
        
    def handleDebuggingStarted(self):
        """
        Public slot to handle the start of a debugging session.
        
        This slot sets the variables filter expressions.
        """
        self.__setGlobalsFilter()
        self.__setLocalsFilter()
        self.showVariablesTab(False)
        
    def currentWidget(self):
        """
        Public method to get a reference to the current widget.
        
        @return reference to the current widget (QWidget)
        """
        return self.__tabWidget.currentWidget()
        
    def setCurrentWidget(self, widget):
        """
        Public slot to set the current page based on the given widget.
        
        @param widget reference to the widget (QWidget)
        """
        self.__tabWidget.setCurrentWidget(widget)
        
    def showThreadList(self, currentID, threadList):
        """
        Public method to show the thread list.
        
        @param currentID id of the current thread (integer)
        @param threadList list of dictionaries containing the thread data
        """
        citm = None
        
        self.__threadList.clear()
        for thread in threadList:
            if thread['broken']:
                state = self.tr("waiting at breakpoint")
            else:
                state = self.tr("running")
            itm = QTreeWidgetItem(self.__threadList,
                                  ["{0:d}".format(thread['id']),
                                   thread['name'], state])
            if thread['id'] == currentID:
                citm = itm
        
        self.__threadList.header().resizeSections(QHeaderView.ResizeToContents)
        self.__threadList.header().setStretchLastSection(True)
        
        if citm:
            self.__doThreadListUpdate = False
            self.__threadList.setCurrentItem(citm)
            self.__doThreadListUpdate = True
        
    def __threadSelected(self, current, previous):
        """
        Private slot to handle the selection of a thread in the thread list.
        
        @param current reference to the new current item (QTreeWidgetItem)
        @param previous reference to the previous current item
            (QTreeWidgetItem)
        """
        if current is not None and self.__doThreadListUpdate:
            tid = int(current.text(0))
            self.debugServer.remoteSetThread(tid)
    
    def __callStackFrameSelected(self, frameNo):
        """
        Private slot to handle the selection of a call stack entry of the
        call stack viewer.
        
        @param frameNo frame number (index) of the selected entry (integer)
        """
        if frameNo >= 0:
            self.stackComboBox.setCurrentIndex(frameNo)
class MotorizedLinearPoti(COMCUPluginBase):
    def __init__(self, *args):
        super().__init__(BrickletMotorizedLinearPoti, *args)

        self.mp = self.device

        self.cbe_position = CallbackEmulator(self.mp.get_position,
                                             None,
                                             self.cb_position,
                                             self.increase_error_count)

        self.current_position = CurveValueWrapper()

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, 100)
        self.slider.setMinimumWidth(200)
        self.slider.setEnabled(False)

        plots = [('Potentiometer Position', Qt.red, self.current_position, str)]
        self.plot_widget = PlotWidget('Position', plots, extra_key_widgets=[self.slider],
                                      update_interval=0.025, y_resolution=1.0)

        self.motor_slider = QSlider(Qt.Horizontal)
        self.motor_slider.setRange(0, 100)
        self.motor_slider.valueChanged.connect(self.motor_slider_value_changed)
        self.motor_hold_position = QCheckBox("Hold Position")
        self.motor_drive_mode = QComboBox()
        self.motor_drive_mode.addItem('Fast')
        self.motor_drive_mode.addItem('Smooth')

        def get_motor_slider_value():
            return self.motor_slider.value()

        self.motor_hold_position.stateChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value()))
        self.motor_drive_mode.currentIndexChanged.connect(lambda x: self.motor_slider_value_changed(get_motor_slider_value()))

        self.motor_position_label = MotorPositionLabel('Motor Target Position:')

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.motor_position_label)
        hlayout.addWidget(self.motor_slider)
        hlayout.addWidget(self.motor_drive_mode)
        hlayout.addWidget(self.motor_hold_position)

        line = QFrame()
        line.setObjectName("line")
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(hlayout)

    def start(self):
        async_call(self.mp.get_motor_position, None, self.get_motor_position_async, self.increase_error_count)

        self.cbe_position.set_period(25)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_position.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletMotorizedLinearPoti.DEVICE_IDENTIFIER

    def cb_position(self, position):
        self.current_position.value = position
        self.slider.setValue(position)

    def get_motor_position_async(self, motor):
        self.motor_slider.blockSignals(True)
        self.motor_hold_position.blockSignals(True)
        self.motor_drive_mode.blockSignals(True)

        self.motor_hold_position.setChecked(motor.hold_position)
        self.motor_drive_mode.setCurrentIndex(motor.drive_mode)
        self.motor_position_label.setText(str(motor.position))
        self.motor_slider.setValue(motor.position)

        self.motor_slider.blockSignals(False)
        self.motor_hold_position.blockSignals(False)
        self.motor_drive_mode.blockSignals(False)

    def motor_slider_value_changed(self, position):
        self.motor_position_label.setText(str(position))
        self.mp.set_motor_position(self.motor_slider.value(), self.motor_drive_mode.currentIndex(), self.motor_hold_position.isChecked())
class ParamsByType(QWidget, MooseWidget):
    """
    Has a QComboBox for the different allowed types.
    On switching type a new ParamsByGroup is shown.
    """
    needBlockList = pyqtSignal(list)
    blockRenamed = pyqtSignal(object, str)
    changed = pyqtSignal()

    def __init__(self, block, **kwds):
        """
        Constructor.
        Input:
            block[BlockInfo]: The block to show.
        """
        super(ParamsByType, self).__init__(**kwds)
        self.block = block
        self.combo = QComboBox()
        self.types = []
        self.type_params_map = {}
        self.table_stack = QStackedWidget()
        self.type_table_map = {}

        for t in sorted(self.block.types.keys()):
            self.types.append(t)
            params_list = []
            for p in self.block.parameters_list:
                params_list.append(self.block.parameters[p])
            t_block = self.block.types[t]
            for p in t_block.parameters_list:
                params_list.append(t_block.parameters[p])
            self.type_params_map[t] = params_list

        self.combo.addItems(sorted(self.block.types.keys()))
        self.combo.currentTextChanged.connect(self.setBlockType)

        self.top_layout = WidgetUtils.addLayout(vertical=True)
        self.top_layout.addWidget(self.combo)
        self.top_layout.addWidget(self.table_stack)
        self.setLayout(self.top_layout)
        self.user_params = []
        self.setDefaultBlockType()

        self.setup()

    def _syncUserParams(self, current, to):
        """
        Sync user added parameters that are on the main block into
        each type ParamsByGroup.
        Input:
            current[ParamsByGroup]: The current group parameter table
            to[ParamsByGroup]: The new group parameter table
        """
        ct = current.findTable("Main")
        tot = to.findTable("Main")
        if not ct or not tot or ct == tot:
            return
        # first remove user params in tot
        tot.removeUserParams()
        params = ct.getUserParams()
        tot.addUserParams(params)
        idx = ct.findRow("Name")
        if idx >= 0:
            name = ct.item(idx, 1).text()
            idx = tot.findRow("Name")
            if idx >= 0:
                tot.item(idx, 1).setText(name)

    def currentType(self):
        return self.combo.currentText()

    def save(self):
        """
        Look at the user params in self.block.parameters.
        update the type tables
        Save type on block
        """
        t = self.getTable()
        if t:
            t.save()
            self.block.setBlockType(self.combo.currentText())

    def reset(self):
        t = self.getTable()
        t.reset()

    def getOrCreateTypeTable(self, type_name):
        """
        Gets the table for the type name or create it if it doesn't exist.
        Input:
            type_name[str]: Name of the type
        Return:
            ParamsByGroup: The parameters corresponding to the type
        """
        t = self.type_table_map.get(type_name)
        if t:
            return t
        t = ParamsByGroup(self.block, self.type_params_map.get(type_name, self.block.orderedParameters()))
        t.needBlockList.connect(self.needBlockList)
        t.blockRenamed.connect(self.blockRenamed)
        t.changed.connect(self.changed)
        self.type_table_map[type_name] = t
        self.table_stack.addWidget(t)
        return t

    def setDefaultBlockType(self):
        param = self.block.getParamInfo("type")
        if param and param.value:
            self.setBlockType(param.value)
        elif self.block.types:
            self.setBlockType(sorted(self.block.types.keys())[0])

    def setBlockType(self, type_name):
        if type_name not in self.block.types:
            return
        t = self.getOrCreateTypeTable(type_name)
        t.updateWatchers()
        self.combo.blockSignals(True)
        self.combo.setCurrentText(type_name)
        self.combo.blockSignals(False)
        t.updateType(type_name)
        current = self.table_stack.currentWidget()
        self._syncUserParams(current, t)
        self.table_stack.setCurrentWidget(t)
        self.changed.emit()

    def addUserParam(self, param):
        t = self.table_stack.currentWidget()
        t.addUserParam(param)

    def setWatchedBlockList(self, path, children):
        for i in range(self.table_stack.count()):
            t = self.table_stack.widget(i)
            t.setWatchedBlockList(path, children)

    def updateWatchers(self):
        for i in range(self.table_stack.count()):
            t = self.table_stack.widget(i)
            t.updateWatchers()

    def getTable(self):
        return self.table_stack.currentWidget()

    def paramValue(self, name):
        for i in range(self.table_stack.count()):
            t = self.table_stack.widget(i)
            if t.paramValue(name):
                return t.paramValue(name)
Beispiel #26
0
class MainWindow(QMainWindow, Ui_MainWindow):
    """
    classdocs
    """

    def __init__(self, app):
        """
        Init
        :param sakia.core.app.Application app: application
        :type: sakia.core.app.Application
        """
        # Set up the user interface from Designer.
        super().__init__()
        self.app = app
        self.initialized = False
        self.password_asker = None
        self.import_dialog = None

        super().setupUi(self)

        QApplication.setWindowIcon(QIcon(":/icons/sakia_logo"))

        self.app.version_requested.connect(self.latest_version_requested)

        self.status_label = QLabel("", self)
        self.status_label.setTextFormat(Qt.RichText)
        self.statusbar.addPermanentWidget(self.status_label, 1)

        self.label_time = QLabel("", self)
        self.statusbar.addPermanentWidget(self.label_time)

        self.combo_referential = QComboBox(self)
        self.combo_referential.setEnabled(False)
        self.combo_referential.currentIndexChanged.connect(self.referential_changed)
        self.statusbar.addPermanentWidget(self.combo_referential)

        self.homescreen = HomeScreenWidget(self.app, self.status_label)
        self.homescreen.frame_communities.community_tile_clicked.connect(self.change_community)
        self.homescreen.toolbutton_new_account.clicked.connect(self.open_add_account_dialog)
        self.homescreen.toolbutton_new_account.addAction(self.action_add_account)
        self.homescreen.toolbutton_new_account.addAction(self.action_import)
        self.homescreen.button_add_community.clicked.connect(self.action_open_add_community)
        self.homescreen.button_disconnect.clicked.connect(lambda :self.action_change_account(""))
        self.centralWidget().layout().addWidget(self.homescreen)
        self.homescreen.toolbutton_connect.setMenu(self.menu_change_account)

        self.community_view = CommunityWidget(self.app, self.status_label)
        self.community_view.button_home.clicked.connect(lambda: self.change_community(None))
        self.community_view.button_certification.clicked.connect(self.open_certification_dialog)
        self.community_view.button_send_money.clicked.connect(self.open_transfer_money_dialog)
        self.centralWidget().layout().addWidget(self.community_view)

    def startup(self):
        self.update_time()
        # FIXME : Need python 3.5 self.app.get_last_version()
        if self.app.preferences['maximized']:
            self.showMaximized()
        else:
            self.show()
        if self.app.current_account:
            self.password_asker = PasswordAskerDialog(self.app.current_account)
            self.community_view.change_account(self.app.current_account, self.password_asker)
        self.refresh()

    @asyncify
    @asyncio.coroutine
    def open_add_account_dialog(self, checked=False):
        dialog = ProcessConfigureAccount(self.app, None)
        result = yield from dialog.async_exec()
        if result == QDialog.Accepted:
            self.action_change_account(self.app.current_account.name)

    @asyncify
    @asyncio.coroutine
    def open_configure_account_dialog(self, checked=False):
        dialog = ProcessConfigureAccount(self.app, self.app.current_account)
        result = yield from dialog.async_exec()
        if result == QDialog.Accepted:
            if self.app.current_account:
                self.action_change_account(self.app.current_account.name)
            else:
                self.refresh()

    @pyqtSlot(str)
    def display_error(self, error):
        QMessageBox.critical(self, ":(",
                             error,
                             QMessageBox.Ok)

    @pyqtSlot(str)
    def referential_changed(self, index):
        if self.app.current_account:
            self.app.current_account.set_display_referential(index)
            if self.community_view:
                self.community_view.referential_changed()
                self.homescreen.referential_changed()

    @pyqtSlot()
    def update_time(self):
        dateTime = QDateTime.currentDateTime()
        self.label_time.setText("{0}".format(QLocale.toString(
                        QLocale(),
                        QDateTime.currentDateTime(),
                        QLocale.dateTimeFormat(QLocale(), QLocale.NarrowFormat)
                    )))
        timer = QTimer()
        timer.timeout.connect(self.update_time)
        timer.start(1000)

    @pyqtSlot()
    def delete_contact(self):
        contact = self.sender().data()
        self.app.current_account.contacts.remove(contact)
        self.refresh_contacts()

    @pyqtSlot()
    def edit_contact(self):
        index = self.sender().data()
        dialog = ConfigureContactDialog(self.app.current_account, self, None, index)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()

    def action_change_account(self, account_name):
        self.app.change_current_account(self.app.get_account(account_name))
        self.password_asker = PasswordAskerDialog(self.app.current_account)
        self.community_view.change_account(self.app.current_account, self.password_asker)
        self.refresh()

    @pyqtSlot()
    def action_open_add_community(self):
        dialog = ProcessConfigureCommunity(self.app,
                                           self.app.current_account, None,
                                           self.password_asker)
        if dialog.exec_() == QDialog.Accepted:
            self.app.save(self.app.current_account)
            dialog.community.start_coroutines()
            self.homescreen.refresh()

    def open_transfer_money_dialog(self):
        dialog = TransferMoneyDialog(self.app,
                                     self.app.current_account,
                                     self.password_asker,
                                     self.community_view.community,
                                     None)
        if dialog.exec_() == QDialog.Accepted:
            self.community_view.tab_history.table_history.model().sourceModel().refresh_transfers()

    def open_certification_dialog(self):
        dialog = CertificationDialog(self.app,
                                     self.app.current_account,
                                     self.password_asker)
        dialog.exec_()

    def open_add_contact_dialog(self):
        dialog = ConfigureContactDialog(self.app.current_account, self)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()

    def open_preferences_dialog(self):
        dialog = PreferencesDialog(self.app)
        result = dialog.exec_()

    def open_about_popup(self):
        """
        Open about popup window
        """
        aboutDialog = QDialog(self)
        aboutUi = Ui_AboutPopup()
        aboutUi.setupUi(aboutDialog)

        latest = self.app.available_version
        version_info = ""
        version_url = ""
        if not latest[0]:
            version_info = self.tr("Latest release : {version}") \
                .format(version=latest[1])
            version_url = latest[2]

            new_version_text = """
                <p><b>{version_info}</b></p>
                <p><a href="{version_url}">{link_text}</a></p>
                """.format(version_info=version_info,
                            version_url=version_url,
                            link_text=self.tr("Download link"))
        else:
            new_version_text = ""

        text = self.tr("""
        <h1>sakia</h1>

        <p>Python/Qt uCoin client</p>

        <p>Version : {:}</p>
        {new_version_text}

        <p>License : GPLv3</p>

        <p><b>Authors</b></p>

        <p>inso</p>
        <p>vit</p>
        <p>Moul</p>
        <p>canercandan</p>
        """).format(__version__, new_version_text=new_version_text)

        aboutUi.label.setText(text)
        aboutDialog.show()

    @pyqtSlot()
    def latest_version_requested(self):
        latest = self.app.available_version
        logging.debug("Latest version requested")
        if not latest[0]:
            version_info = self.tr("Please get the latest release {version}") \
                .format(version=latest[1])
            version_url = latest[2]

            if self.app.preferences['notifications']:
                toast.display("sakia", """{version_info}""".format(
                version_info=version_info,
                version_url=version_url))

    @pyqtSlot(Community)
    def change_community(self, community):
        if community:
            self.homescreen.hide()
            self.community_view.show()
        else:
            self.community_view.hide()
            self.homescreen.show()

        self.community_view.change_community(community)

    def refresh_accounts(self):
        self.menu_change_account.clear()
        for account_name in sorted(self.app.accounts.keys()):
            action = QAction(account_name, self)
            action.triggered.connect(lambda checked, account_name=account_name: self.action_change_account(account_name))
            self.menu_change_account.addAction(action)

    def refresh_contacts(self):
        self.menu_contacts_list.clear()
        if self.app.current_account:
            for index, contact in enumerate(self.app.current_account.contacts):
                contact_menu = self.menu_contacts_list.addMenu(contact['name'])
                edit_action = contact_menu.addAction(self.tr("Edit"))
                edit_action.triggered.connect(self.edit_contact)
                edit_action.setData(index)
                delete_action = contact_menu.addAction(self.tr("Delete"))
                delete_action.setData(contact)
                delete_action.triggered.connect(self.delete_contact)

    def refresh(self):
        """
        Refresh main window
        When the selected account changes, all the widgets
        in the window have to be refreshed
        """
        logging.debug("Refresh started")
        self.refresh_accounts()
        self.community_view.hide()
        self.homescreen.show()
        self.homescreen.refresh()

        if self.app.current_account is None:
            self.setWindowTitle(self.tr("sakia {0}").format(__version__))
            self.action_add_a_contact.setEnabled(False)
            self.actionCertification.setEnabled(False)
            self.actionTransfer_money.setEnabled(False)
            self.action_configure_parameters.setEnabled(False)
            self.action_set_as_default.setEnabled(False)
            self.menu_contacts_list.setEnabled(False)
            self.combo_referential.setEnabled(False)
            self.status_label.setText(self.tr(""))
            self.password_asker = None
        else:
            self.password_asker = PasswordAskerDialog(self.app.current_account)

            self.combo_referential.blockSignals(True)
            self.combo_referential.clear()
            for ref in money.Referentials:
                self.combo_referential.addItem(ref.translated_name())

            self.combo_referential.setEnabled(True)
            self.combo_referential.blockSignals(False)
            logging.debug(self.app.preferences)
            self.combo_referential.setCurrentIndex(self.app.preferences['ref'])
            self.action_add_a_contact.setEnabled(True)
            self.actionCertification.setEnabled(True)
            self.actionTransfer_money.setEnabled(True)
            self.menu_contacts_list.setEnabled(True)
            self.action_configure_parameters.setEnabled(True)
            self.setWindowTitle(self.tr("sakia {0} - Account : {1}").format(__version__,
                                                                               self.app.current_account.name))

        self.refresh_contacts()

    def import_account(self):
        self.import_dialog = ImportAccountDialog(self.app, self)
        self.import_dialog.accepted.connect(self.import_account_accepted)
        self.import_dialog.exec_()

    def import_account_accepted(self):
        # open account after import
        self.action_change_account(self.import_dialog.edit_name.text())

    def export_account(self):
        # Testable way of using a QFileDialog
        export_dialog = QFileDialog(self)
        export_dialog.setObjectName('ExportFileDialog')
        export_dialog.setWindowTitle(self.tr("Export an account"))
        export_dialog.setNameFilter(self.tr("All account files (*.acc)"))
        export_dialog.setLabelText(QFileDialog.Accept, self.tr('Export'))
        export_dialog.setOption(QFileDialog.DontUseNativeDialog, True)
        export_dialog.accepted.connect(self.export_account_accepted)
        export_dialog.show()

    def export_account_accepted(self):
        export_dialog = self.sender()
        selected_file = export_dialog.selectedFiles()
        if selected_file:
            if selected_file[0][-4:] == ".acc":
                path = selected_file[0]
            else:
                path = selected_file[0] + ".acc"
            self.app.export_account(path, self.app.current_account)

    def closeEvent(self, event):
        self.app.stop()
        super().closeEvent(event)

    def changeEvent(self, event):
        """
        Intercepte LanguageChange event to translate UI
        :param QEvent QEvent: Event
        :return:
        """
        if event.type() == QEvent.LanguageChange:
            self.retranslateUi(self)
            self.refresh()
        return super(MainWindow, self).changeEvent(event)
Beispiel #27
0
class DistanceIRV2(COMCUPluginBase):
    NUM_VALUES = 512
    DIVIDER = 2**12//NUM_VALUES

    def __init__(self, *args):
        super().__init__(BrickletDistanceIRV2, *args)

        self.dist = self.device

        self.cbe_distance = CallbackEmulator(self.dist.get_distance,
                                             None,
                                             self.cb_distance,
                                             self.increase_error_count)
        self.cbe_analog_value = CallbackEmulator(self.dist.get_analog_value,
                                                 None,
                                                 self.cb_analog_value,
                                                 self.increase_error_count)

        self.analog_label = AnalogLabel('Analog Value:')
        hlayout = QHBoxLayout()
        self.average_label = QLabel('Moving Average Length:')
        self.average_spin = QSpinBox()
        self.average_spin.setMinimum(1)
        self.average_spin.setMaximum(1000)
        self.average_spin.setSingleStep(1)
        self.average_spin.setValue(25)
        self.average_spin.editingFinished.connect(self.average_spin_finished)

        self.sensor_label = QLabel('Sensor Type:')
        self.sensor_combo = QComboBox()
        self.sensor_combo.addItem('2Y0A41 (4-30cm)')
        self.sensor_combo.addItem('2Y0A21 (10-80cm)')
        self.sensor_combo.addItem('2Y0A02 (20-150cm)')
        self.sensor_combo.currentIndexChanged.connect(self.sensor_combo_changed)

        hlayout.addWidget(self.average_label)
        hlayout.addWidget(self.average_spin)
        hlayout.addStretch()
        hlayout.addWidget(self.sensor_label)
        hlayout.addWidget(self.sensor_combo)

        self.current_distance = CurveValueWrapper() # float, cm

        plots = [('Distance', Qt.red, self.current_distance, '{} cm'.format)]
        self.plot_widget = PlotWidget('Distance [cm]', plots, extra_key_widgets=[self.analog_label], y_resolution=0.1)

        line = QFrame()
        line.setObjectName("line")
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        layout = QVBoxLayout(self)
        layout.addWidget(self.plot_widget)
        layout.addWidget(line)
        layout.addLayout(hlayout)

    def sensor_combo_changed(self, index):
        self.dist.set_sensor_type(index)

    def average_spin_finished(self):
        self.dist.set_moving_average_configuration(self.average_spin.value())

    def get_moving_average_configuration_async(self, average):
        self.average_spin.blockSignals(True)
        self.average_spin.setValue(average)
        self.average_spin.blockSignals(False)

    def get_sensor_type_async(self, sensor):
        self.sensor_combo.blockSignals(True)
        self.sensor_combo.setCurrentIndex(sensor)
        self.sensor_combo.blockSignals(False)

    def start(self):
        async_call(self.dist.get_moving_average_configuration, None, self.get_moving_average_configuration_async, self.increase_error_count)
        async_call(self.dist.get_sensor_type, None, self.get_sensor_type_async, self.increase_error_count)

        self.cbe_distance.set_period(10)
        self.cbe_analog_value.set_period(100)

        self.plot_widget.stop = False

    def stop(self):
        self.cbe_distance.set_period(0)
        self.cbe_analog_value.set_period(0)

        self.plot_widget.stop = True

    def destroy(self):
        pass

    @staticmethod
    def has_device_identifier(device_identifier):
        return device_identifier == BrickletDistanceIRV2.DEVICE_IDENTIFIER

    def cb_distance(self, distance):
        self.current_distance.value = distance / 10.0

    def cb_analog_value(self, analog_value):
        self.analog_label.setText(analog_value)
Beispiel #28
0
class MetricsToolBar(QToolBar):
    """
    Emits *pointSizeChanged*.
    """
    glyphsChanged = pyqtSignal(list)
    settingsChanged = pyqtSignal(dict)

    def __init__(self, font, parent=None):
        super().__init__(parent)
        auxiliaryWidth = self.fontMetrics().width('0') * 8
        self.leftTextField = MetricsSequenceEdit(font, self)
        self.leftTextField.setMaximumWidth(auxiliaryWidth)
        self.textField = MetricsSequenceComboBox(font, self)
        # XXX: had to use Maximum because Preferred did extend the widget(?)
        self.textField.setSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Maximum)
        self.rightTextField = MetricsSequenceEdit(font, self)
        self.rightTextField.setMaximumWidth(auxiliaryWidth)
        self.leftTextField.textEdited.connect(self.textField.editTextChanged)
        self.rightTextField.textEdited.connect(self.textField.editTextChanged)
        self.textField.editTextChanged.connect(self._textChanged)

        self.comboBox = QComboBox(self)
        self.comboBox.setEditable(True)
        self.comboBox.setCompleter(None)
        self.comboBox.setValidator(QIntValidator(self))
        for p in pointSizes:
            self.comboBox.addItem(str(p))
        self.pointSizeChanged = self.comboBox.currentIndexChanged[str]

        self.configBar = QPushButton(self)
        self.configBar.setFlat(True)
        self.configBar.setIcon(QIcon(":settings.svg"))
        self.configBar.setStyleSheet("padding: 2px 0px; padding-right: 10px")
        self.toolsMenu = QMenu(self)
        self._showKerning = self.toolsMenu.addAction(
            self.tr("Show Kerning"), self._kerningVisibilityChanged)
        self._showKerning.setCheckable(True)
        self._showMetrics = self.toolsMenu.addAction(self.tr("Show Metrics"),
                                                     self._controlsTriggered)
        self._showMetrics.setCheckable(True)
        self.toolsMenu.addSeparator()
        self._verticalFlip = self.toolsMenu.addAction(self.tr("Vertical Flip"),
                                                      self._controlsTriggered)
        self._verticalFlip.setCheckable(True)
        self._wrapLines = self.toolsMenu.addAction(self.tr("Wrap Lines"),
                                                   self._controlsTriggered)
        self._wrapLines.setCheckable(True)
        self.toolsMenu.addSeparator()
        action = self.toolsMenu.addAction(self.tr("Line Height:"))
        action.setEnabled(False)
        lineHeight = QWidgetAction(self.toolsMenu)
        self._lineHeightSlider = slider = QSlider(Qt.Horizontal, self)
        # QSlider works with integers so we'll just divide what comes out of it
        # by 100
        slider.setMinimum(80)
        slider.setMaximum(160)
        slider.setValue(110)
        slider.valueChanged.connect(self._controlsTriggered)
        slider.valueChanged.connect(self._sliderLineHeightChanged)
        lineHeight.setDefaultWidget(slider)
        self.toolsMenu.addAction(lineHeight)
        self.configBar.setMenu(self.toolsMenu)

        self.addWidget(self.leftTextField)
        self.addWidget(self.textField)
        self.addWidget(self.rightTextField)
        self.addWidget(self.comboBox)
        self.addWidget(self.configBar)

        app = QApplication.instance()
        app.dispatcher.addObserver(self, "_currentGlyphChanged",
                                   "currentGlyphChanged")

        self.readSettings()

    def readSettings(self):
        items = settings.metricsWindowComboBoxItems()
        self.textField.clear()
        self.textField.addItems(items)

    # -------------
    # Notifications
    # -------------

    # app

    def _currentGlyphChanged(self, notification):
        self._textChanged()

    # widget

    def _controlsTriggered(self):
        params = dict(
            lineHeight=self._lineHeightSlider.value() / 100,
            showKerning=self._showKerning.isChecked(),
            showMetrics=self._showMetrics.isChecked(),
            verticalFlip=self._verticalFlip.isChecked(),
            wrapLines=self._wrapLines.isChecked(),
        )
        self.settingsChanged.emit(params)

    def _kerningVisibilityChanged(self):
        self._controlsTriggered()
        # if showKerning was triggered, it won't apply until we pipe the glyphs
        # again. do so
        self._textChanged()

    def _sliderLineHeightChanged(self, value):
        QToolTip.showText(QCursor.pos(), str(value / 100), self)

    def _textChanged(self):
        leftGlyphs = self.leftTextField.glyphs()
        rightGlyphs = self.rightTextField.glyphs()
        glyphs = self.textField.glyphs()
        ret = []
        for glyph in glyphs:
            ret.extend(leftGlyphs + [glyph] + rightGlyphs)
        self.glyphsChanged.emit(ret)

    # --------------
    # Public methods
    # --------------

    def setPointSize(self, pointSize):
        self.comboBox.blockSignals(True)
        self.comboBox.setEditText(str(pointSize))
        self.comboBox.blockSignals(False)

    def setText(self, text, left=None, right=None):
        self.leftTextField.setText(left)
        self.rightTextField.setText(right)
        self.textField.setEditText(text)

    def setWrapLines(self, value):
        self._wrapLines.setChecked(value)
        self._controlsTriggered()

    # TODO: more methods

    # ----------
    # Qt methods
    # ----------

    def closeEvent(self, event):
        super().closeEvent(event)
        if event.isAccepted():
            app = QApplication.instance()
            app.dispatcher.removeObserver(self, "currentGlyphChanged")

    def showEvent(self, event):
        super().showEvent(event)
        self.textField.setFocus(Qt.OtherFocusReason)
class ApplicationPage(QWidget):
    """ The GUI for the application page of a project. """

    # The page's label.
    label = "Application Source"

    # Emitted when the user changes the PyQt version.
    pyqt_version_changed = pyqtSignal(bool)

    # Emitted when the user changes the Python target version.
    python_target_version_changed = pyqtSignal()

    @property
    def project(self):
        """ The project property getter. """

        return self._project

    @project.setter
    def project(self, value):
        """ The project property setter. """

        if self._project != value:
            self._project = value
            self._script_edit.set_project(value)
            self._package_edit.set_project(value)
            self._update_page()

    def __init__(self):
        """ Initialise the page. """

        super().__init__()

        self._project = None

        # Create the page's GUI.
        layout = QGridLayout()

        form = BetterForm()

        self._name_edit = QLineEdit(
                placeholderText="Application name",
                whatsThis="The name of the application. It will default to "
                        "the base name of the application script without any "
                        "extension.",
                textEdited=self._name_changed)
        form.addRow("Name", self._name_edit)

        self._script_edit = FilenameEditor("Application Script",
                placeholderText="Application script",
                whatsThis="The name of the application's optional main script "
                        "file.",
                textEdited=self._script_changed)
        form.addRow("Main script file", self._script_edit)

        self._entry_point_edit = QLineEdit(
                placeholderText="Entry point in application package",
                whatsThis="The name of the optional entry point in the "
                        "application's package.",
                textEdited=self._entry_point_changed)
        form.addRow("Entry point", self._entry_point_edit)

        self._sys_path_edit = QLineEdit(
                placeholderText="Additional sys.path directories",
                whatsThis="A space separated list of additional directories, "
                        "ZIP files and eggs to add to <tt>sys.path</tt>. Only "
                        "set this if you want to allow external packages to "
                        "be imported.",
                textEdited=self._sys_path_changed)
        form.addRow("sys.path", self._sys_path_edit)

        layout.addLayout(form, 0, 0)

        options_layout = BetterForm()

        self._py_version_edit = QComboBox(
                whatsThis="Select the target Python version.")
        self._py_version_edit.addItems(get_supported_python_versions())
        self._py_version_edit.currentIndexChanged.connect(
                self._py_version_changed)
        options_layout.addRow("Target Python version", self._py_version_edit)

        self._pyqt_version_edit = QComboBox(
                whatsThis="Select the PyQt version.")
        self._pyqt_version_edit.addItems(["PyQt4", "PyQt5"])
        self._pyqt_version_edit.currentIndexChanged.connect(
                self._pyqt_version_changed)
        options_layout.addRow("Target PyQt version", self._pyqt_version_edit)

        self._console_edit = QCheckBox("Use console (Windows)",
                whatsThis="Enable console output for Windows applications. "
                        "Console output will be enabled automatically if no "
                        "graphical PyQt modules are used.",
                stateChanged=self._console_changed)
        options_layout.addRow(self._console_edit)

        self._bundle_edit = QCheckBox("Application bundle (OS X)",
                whatsThis="Build an application bundle on OS X. If it is not "
                        "checked then the application will be built as a "
                        "simple executable.",
                stateChanged=self._bundle_changed)
        options_layout.addRow(self._bundle_edit)

        layout.addLayout(options_layout, 0, 1)

        self._package_edit = _ApplicationPackageEditor()
        self._package_edit.package_changed.connect(self._package_changed)
        package_edit_gb = QGroupBox(self._package_edit.title)
        package_edit_gb.setLayout(self._package_edit)
        layout.addWidget(package_edit_gb, 1, 0, 1, 2)
        layout.setRowStretch(1, 1)

        self.setLayout(layout)

    def _update_page(self):
        """ Update the page using the current project. """

        project = self.project

        self._name_edit.setText(project.application_name)
        self._script_edit.setText(project.application_script)
        self._entry_point_edit.setText(project.application_entry_point)
        self._sys_path_edit.setText(project.sys_path)
        self._package_edit.configure(project.application_package, project)

        blocked = self._py_version_edit.blockSignals(True)
        self._py_version_edit.setCurrentIndex(
                get_supported_python_version_index(
                        project.python_target_version))
        self._py_version_edit.blockSignals(blocked)

        blocked = self._pyqt_version_edit.blockSignals(True)
        self._pyqt_version_edit.setCurrentIndex(
                1 if project.application_is_pyqt5 else 0)
        self._pyqt_version_edit.blockSignals(blocked)

        blocked = self._console_edit.blockSignals(True)
        self._console_edit.setCheckState(
                Qt.Checked if project.application_is_console else Qt.Unchecked)
        self._console_edit.blockSignals(blocked)

        blocked = self._bundle_edit.blockSignals(True)
        self._bundle_edit.setCheckState(
                Qt.Checked if project.application_is_bundle else Qt.Unchecked)
        self._bundle_edit.blockSignals(blocked)

    def _py_version_changed(self, idx):
        """ Invoked when the user changes the Python version number. """

        self.project.python_target_version = get_supported_python_version(idx)
        self.project.modified = True

        self.python_target_version_changed.emit()

    def _pyqt_version_changed(self, idx):
        """ Invoked when the user changes the PyQt version number. """

        pyqt5 = (idx == 1)
        self.project.application_is_pyqt5 = pyqt5
        self.project.modified = True

        self.pyqt_version_changed.emit(pyqt5)

    def _console_changed(self, state):
        """ Invoked when the user changes the console state. """

        self.project.application_is_console = (state == Qt.Checked)
        self.project.modified = True

    def _bundle_changed(self, state):
        """ Invoked when the user changes the bundle state. """

        self.project.application_is_bundle = (state == Qt.Checked)
        self.project.modified = True

    def _name_changed(self, value):
        """ Invoked when the user edits the application name. """

        self.project.application_name = value
        self.project.modified = True

    def _script_changed(self, value):
        """ Invoked when the user edits the application script name. """

        self.project.application_script = value
        self.project.modified = True

    def _entry_point_changed(self, value):
        """ Invoked when the user edits the entry point. """

        self.project.application_entry_point = value
        self.project.modified = True

    def _sys_path_changed(self, value):
        """ Invoked when the user edits the sys.path directories. """

        self.project.sys_path = value.strip()
        self.project.modified = True

    def _package_changed(self):
        """ Invoked when the user edits the application package. """

        self.project.modified = True
Beispiel #30
0
class FileWranglerApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.targetDir = FileChooserTextBox("Destination: ", "Select destination directory", True)

        self.move_button = QPushButton(ActionKeys.move.value)
        self.move_button.pressed.connect(partial(self.execute_merge, ActionKeys.move.value))
        self.copy_button = QPushButton(ActionKeys.copy.value)
        self.copy_button.pressed.connect(partial(self.execute_merge, ActionKeys.copy.value))
        self.progress_bar = QProgressBar()
        self.date_checkbox = QCheckBox("Append Date (YYYY.MM.DD) to destination file")
        self.delete_source_checkbox = QCheckBox("After move, delete Source directories if empty")
        self.dir_include = QSpinBox()
        self.dir_include.setMinimum(0)
        self.dir_include.setValue(0)
        self.dir_include.setMaximum(10)
        self.sort_name = QRadioButton("Name")
        self.sort_name.setChecked(True)
        self.sort_date = QRadioButton("Date")
        self.sort_size = QRadioButton("Size")
        self.sort_none = QRadioButton("None")
        self.key_token_string = QComboBox()
        self.key_token_string.setEditable(True)
        self.key_token_string.setInsertPolicy(QComboBox.InsertAtTop)
        self.key_token_string.setCurrentText(_DEFAULT_REGEX)
        self.key_separator = QRadioButton("Separator")
        self.key_regex = QRadioButton("Regular Expression")
        self.key_regex.setChecked(True)
        self.key_replace = QRadioButton("Completely Replace")
        self.key_match_counter = QSpinBox()
        self.key_match_counter.setMinimum(1)
        self.key_match_counter.setValue(1)
        self.key_match_counter.setMaximum(10)
        self.dropZone = DropZone()

        self.key_match_counter.valueChanged.connect(self.create_merge)
        self.dir_include.valueChanged.connect(self.create_merge)
        self.dropZone.files_dropped_event.connect(self.create_merge)
        self.key_token_string.editTextChanged.connect(self.create_merge)
        self.key_regex.released.connect(partial(self.create_merge))
        self.key_replace.released.connect(partial(self.create_merge))
        self.key_separator.released.connect(partial(self.create_merge))
        self.date_checkbox.stateChanged.connect(self.create_merge)
        self.targetDir.file_selection_changed.connect(self.create_merge)
        self.sort_date.released.connect(partial(self.create_merge))
        self.sort_name.released.connect(partial(self.create_merge))
        self.sort_size.released.connect(partial(self.create_merge))
        self.sort_none.released.connect(partial(self.create_merge))
        self.table = MainTable()
        self.init_ui()

    def init_ui(self):
        def create_dropzone_groupbox():
            dropzone_sort_layout = QHBoxLayout()
            dropzone_sort_layout.addWidget(QLabel("Order By"))
            dropzone_sort_layout.addWidget(self.sort_name)
            dropzone_sort_layout.addWidget(self.sort_date)
            dropzone_sort_layout.addWidget(self.sort_size)
            dropzone_sort_layout.addWidget(self.sort_none)
            dropzone_layout = QVBoxLayout()
            dropzone_layout.addWidget(self.dropZone)
            dropzone_layout.addLayout(dropzone_sort_layout)
            dropzone_layout.setContentsMargins(0, 0, 0, 0)

            groupbox = QGroupBox()
            groupbox.setLayout(dropzone_layout)
            return groupbox

        def create_rename_controlbox():
            self.move_button.setIcon(QIcon.fromTheme("edit-paste"))
            self.copy_button.setIcon(QIcon.fromTheme("edit-copy"))

            button_layout = QHBoxLayout()
            button_layout.addWidget(QLabel(""), stretch=1)
            button_layout.addWidget(self.move_button)
            button_layout.addWidget(self.copy_button)

            key_layout = QHBoxLayout()
            key_layout.addWidget(QLabel("Match Key:   "))
            key_layout.addWidget(self.key_match_counter)
            key_layout.addWidget(QLabel("Key Identifier"))
            key_layout.addWidget(self.key_token_string, stretch=1)
            key_layout.addWidget(self.key_regex)
            key_layout.addWidget(self.key_separator)
            key_layout.addWidget(self.key_replace)

            sub_control_layout = QHBoxLayout()
            sub_control_layout.addWidget(QLabel("Dir. names:  "))
            sub_control_layout.addWidget(self.dir_include)
            sub_control_layout.addWidget(self.date_checkbox)
            sub_control_layout.addWidget(self.delete_source_checkbox)
            sub_control_layout.addWidget(QLabel(""), stretch=1)

            control_layout = QVBoxLayout()
            control_layout.addWidget(self.targetDir)
            control_layout.addLayout(key_layout)
            control_layout.addLayout(sub_control_layout)
            # control_layout.addWidget(QLabel(""))
            control_layout.addLayout(button_layout)

            groupbox = QGroupBox()
            groupbox.setLayout(control_layout)
            return groupbox

        top_layout = QHBoxLayout()
        top_layout.addWidget(create_dropzone_groupbox())
        top_layout.addWidget(QVLine())
        top_layout.addWidget(create_rename_controlbox())

        main_layout = QVBoxLayout()
        main_layout.addLayout(top_layout)
        main_layout.addWidget(self.table)
        main_layout.setContentsMargins(2, 2, 2, 2)

        dummy_widget = QWidget()
        dummy_widget.setLayout(main_layout)
        self.setCentralWidget(dummy_widget)

        self.setWindowTitle('File Wrangler')
        self.setMinimumWidth(1724)
        self.setMinimumHeight(768)
        self.show()

    def create_merge(self):
        token_string = self.key_token_string.currentText()
        if token_string is None or token_string == "":
            return

        sort_key = SortBy.none
        if self.sort_size.isChecked():
            sort_key = SortBy.size
        elif self.sort_name.isChecked():
            sort_key = SortBy.name
        elif self.sort_date.isChecked():
            sort_key = SortBy.date

        config = {
            ConfigKeys.append_date: self.date_checkbox.isChecked(),
            ConfigKeys.key_token_string: self.key_token_string.currentText(),
            ConfigKeys.key_token_count: self.key_match_counter.value(),
            ConfigKeys.sort_by: sort_key,
            ConfigKeys.dir_include: self.dir_include.value()
        }

        if self.key_regex.isChecked():
            try:
                re.compile(self.key_token_string.currentText())
                config[ConfigKeys.key_type] = KeyType.regular_expression
            except re.error:
                logger.error("Regular expression error")
                return
        elif self.key_replace.isChecked():
            config[ConfigKeys.key_type] = KeyType.replacement
        else:
            config[ConfigKeys.key_type] = KeyType.separator

        try:
            model = create_merge_tree(self.dropZone.dropped_files, self.targetDir.getSelection(), config)
            if model:
                self.table.set_model(model)
        except FileNotFoundError as fne:
            logger.error(f"File not found {fne.filename}")

    def execute_merge(self, action):
        file_items = self.table.model
        transfer_dialog = QProgressDialog()
        transfer_dialog.setWindowModality(Qt.WindowModal)
        transfer_dialog.setWindowTitle(action + " Files")
        transfer_dialog.setCancelButtonText("Abort")
        transfer_dialog.setValue(0)
        transfer_dialog.setMaximum(len(file_items))
        transfer_dialog.setMinimumWidth(550)
        transfer_dialog.setMaximumWidth(self.minimumWidth())
        transfer_dialog.show()
        source_dirs = set()
        for item in file_items:
            source = item[DisplayKeys.source]
            source_dirs.add(os.path.dirname(source))
            target = item[DisplayKeys.target]
            transfer_dialog.setValue(transfer_dialog.value() + 1)
            if self.table.is_selected(source):
                logger.debug(f"{action}: {source} -> {target}")
                transfer_dialog.setLabelText(f"{action}: \n{source} \n->\n {target}")
                # Allow repainting etc.
                QCoreApplication.processEvents()
                if action == ActionKeys.copy.value:
                    shutil.copy(source, target)
                    self.table.remove_file(source)
                elif action == ActionKeys.move.value:
                    shutil.move(source, target)
                    self.table.remove_file(source)
                else:
                    logger.error("Unknown Action! " + action)
            if transfer_dialog.wasCanceled():
                logger.info("User aborted operation")
                break
        self.key_token_string.blockSignals(True)
        self.key_token_string.addItem(self.key_token_string.currentText())
        self.key_token_string.blockSignals(False)

        # Delete Source dirs
        if self.delete_source_checkbox.checkState() == Qt.Checked:
            for _dir in source_dirs:
                if not os.listdir(_dir):
                    logger.info(f"Directory {_dir} is empty. Attempting to delete it")
                    os.rmdir(_dir)
                    logger.info(f"Directory {_dir} is empty. Attempting to delete it - Done")
                else:
                    logger.info(f"Directory {_dir} is not empty, so will not delete it")
Beispiel #31
0
class SchemeSelector(QWidget):

    currentChanged = pyqtSignal()
    changed = pyqtSignal()

    def __init__(self, parent=None):
        super(SchemeSelector, self).__init__(parent)
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.label = QLabel()
        self.scheme = QComboBox()
        self.menuButton = QPushButton(flat=True)
        menu = QMenu(self.menuButton)
        self.menuButton.setMenu(menu)
        layout.addWidget(self.label)
        layout.addWidget(self.scheme)
        layout.addWidget(self.menuButton)
        layout.addStretch(1)
        # action generator
        def act(slot, icon=None):
            a = QAction(self, triggered=slot)
            self.addAction(a)
            icon and a.setIcon(icons.get(icon))
            return a

        # add action
        a = self.addAction_ = act(self.slotAdd, 'list-add')
        menu.addAction(a)

        # remove action
        a = self.removeAction = act(self.slotRemove, 'list-remove')
        menu.addAction(a)


        # rename action
        a = self.renameAction = act(self.slotRename, 'document-edit')
        menu.addAction(a)

        menu.addSeparator()

        # import action
        a = self.importAction = act(self.slotImport, 'document-open')
        menu.addAction(a)

        # export action
        a = self.exportAction = act(self.slotExport, 'document-save-as')
        menu.addAction(a)


        self.scheme.currentIndexChanged.connect(self.slotSchemeChanged)
        app.translateUI(self)

    def translateUI(self):
        self.label.setText(_("Scheme:"))
        self.menuButton.setText(_("&Menu"))
        self.addAction_.setText(_("&Add..."))
        self.removeAction.setText(_("&Remove"))
        self.renameAction.setText(_("Re&name..."))
        self.importAction.setText(_("&Import..."))
        self.exportAction.setText(_("&Export..."))

    def slotSchemeChanged(self, index):
        """Called when the Scheme combobox is changed by the user."""
        self.disableDefault(self.scheme.itemData(index) == 'default')
        self.currentChanged.emit()
        self.changed.emit()

    def disableDefault(self, val):
        self.removeAction.setDisabled(val)
        self.renameAction.setDisabled(val)

    def schemes(self):
        """Returns the list with internal names of currently available schemes."""
        return [self.scheme.itemData(i) for i in range(self.scheme.count())]

    def currentScheme(self):
        """Returns the internal name of the currently selected scheme"""
        return self.scheme.itemData(self.scheme.currentIndex())

    def insertSchemeItem(self, name, scheme):
        for i in range(1, self.scheme.count()):
            n = self.scheme.itemText(i)
            if n.lower() > name.lower():
                self.scheme.insertItem(i, name, scheme)
                break
        else:
            self.scheme.addItem(name, scheme)

    def addScheme(self, name):
        num, key = 1, 'user1'
        while key in self.schemes() or key in self._schemesToRemove:
            num += 1
            key = 'user{0}'.format(num)
        self.insertSchemeItem(name, key)
        self.scheme.setCurrentIndex(self.scheme.findData(key))
        return key

    def slotAdd(self):
        name, ok = QInputDialog.getText(self,
            app.caption(_("Add Scheme")),
            _("Please enter a name for the new scheme:"))
        if ok:
            self.addScheme(name)


    def slotRemove(self):
        index = self.scheme.currentIndex()
        scheme = self.scheme.itemData(index)
        if scheme == 'default':
            return # default can not be removed

        self._schemesToRemove.add(scheme)
        self.scheme.removeItem(index)

    def slotRename(self):
        index = self.scheme.currentIndex()
        name = self.scheme.itemText(index)
        scheme = self.scheme.itemData(index)
        newName, ok = QInputDialog.getText(self, _("Rename"), _("New name:"), text=name)
        if ok:
            self.scheme.blockSignals(True)
            self.scheme.removeItem(index)
            self.insertSchemeItem(newName, scheme)
            self.scheme.setCurrentIndex(self.scheme.findData(scheme))
            self.scheme.blockSignals(False)
            self.changed.emit()

    def slotImport(self):
        filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files"))
        caption = app.caption(_("dialog title", "Import color theme"))
        filename = QFileDialog.getOpenFileName(self, caption, QDir.homePath(), filetypes)[0]
        if filename:
            self.parent().import_(filename)

    def slotExport(self):
        name = self.scheme.currentText()
        filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"), _("All Files"))
        caption = app.caption(_("dialog title",
            "Export {name}").format(name=name))
        path = os.path.join(QDir.homePath(), name+'.xml')
        filename = QFileDialog.getSaveFileName(self, caption, path, filetypes)[0]
        if filename:
            if os.path.splitext(filename)[1] != '.xml':
                filename += '.xml'
            self.parent().export(name, filename)


    def loadSettings(self, currentKey, namesGroup):
        # don't mark schemes for removal anymore
        self._schemesToRemove = set()

        s = QSettings()
        cur = s.value(currentKey, "default", str)

        # load the names for the shortcut schemes
        s.beginGroup(namesGroup)
        block = self.scheme.blockSignals(True)
        self.scheme.clear()
        self.scheme.addItem(_("Default"), "default")
        lst = [(s.value(key, key, str), key) for key in s.childKeys()]
        for name, key in sorted(lst, key=lambda f: f[0].lower()):
            self.scheme.addItem(name, key)

        # find out index
        index = self.scheme.findData(cur)
        self.disableDefault(cur == 'default')
        self.scheme.setCurrentIndex(index)
        self.scheme.blockSignals(block)
        self.currentChanged.emit()

    def saveSettings(self, currentKey, namesGroup, removePrefix=None):
        # first save new scheme names
        s = QSettings()
        s.beginGroup(namesGroup)
        for i in range(self.scheme.count()):
            if self.scheme.itemData(i) != 'default':
                s.setValue(self.scheme.itemData(i), self.scheme.itemText(i))

        for scheme in self._schemesToRemove:
            s.remove(scheme)
        s.endGroup()
        if removePrefix:
            for scheme in self._schemesToRemove:
                s.remove("{0}/{1}".format(removePrefix, scheme))
        # then save current
        scheme = self.currentScheme()
        s.setValue(currentKey, scheme)
        # clean up
        self._schemesToRemove = set()
Beispiel #32
0
class GameControllerWindow(QWidget):
    def __init__(self, model: GameControllerModel,
                 controller: GameControllerController):
        super(QWidget, self).__init__()
        self.toolbar_w = 80
        self.toolbar_h = 80
        self.model = model
        self.controller = controller
        self.main_layout = QGridLayout()
        self.toolbarOptions = QVBoxLayout()
        self.dungeonSelector = QDungeonSelector(self, controller, model)
        # self.widRun = QToolboxRun(self)
        self.currentLevelWidget = QLevelViewer(self.model, 0)
        self.widActions = QToolboxActions(self)
        self.size_info_lbl = QLabel("Screen size:\n1x1")
        self.lblDataFolder = QLabel()
        self.lblConnectionStatus = QLabel()
        self.lblCheckConnectionStatus = QLabel()
        self.controlWidget = QDungeonController(self, controller, model)
        self.content_wid = QDeskArea(self, controller,
                                     model)  # QtWidgets.QWidget()
        self.infoLabel = QLabel()
        self.cBoxhealStrategy = QComboBox()
        self.lblInfoHealStrategy = QLabel()
        # self.setupUi()
        self.initConnectors()
        self.onChangeHealStrategy(self.model.engine.healingStrategy ==
                                  self.model.engine.healingStrategy.AlwaysHeal)
        # self.model.onSourceChanged.connect(self.source_changed)

    def initConnectors(self):
        self.model.engine.gameWon.connect(self.onGameWon)
        self.model.engine.noEnergyLeft.connect(self.onNoEnergyLeft)
        self.model.engineStatechanged.connect(self.onEngineStateChanged)
        self.model.connectionStateChanged.connect(self.onConnectionStateChange)
        self.model.checkConnectionStateChanged.connect(
            self.onCheckConnectionStateChanged)
        self.model.engine.resolutionChanged.connect(self.onScreenDataChanged)
        self.model.engine.dataFolderChanged.connect(self.onScreenDataChanged)
        self.model.engine.levelChanged.connect(self.onLevelChanged)
        self.model.engine.healingStrategyChanged.connect(
            self.onHealingStrategyChange)
        self.cBoxhealStrategy.currentIndexChanged.connect(
            self.onChangeHealStrategy)

    def onHealingStrategyChange(self, always_heal: bool):
        index = 1 if always_heal else 0
        if self.cBoxhealStrategy.currentIndex != index:
            self.cBoxhealStrategy.blockSignals(True)
            self.cBoxhealStrategy.setCurrentIndex(index)
            self.cBoxhealStrategy.blockSignals(False)

    def onChangeHealStrategy(self, new_index):
        self.controller.requestChangeHealingStrategy(new_index == 1)

    def onLevelChanged(self, newLevel):
        self.currentLevelWidget.changeLevel(newLevel)

    def onGameWon(self):
        self.infoLabel.setText("Finished 20 chapters. Win!")

    def onNoEnergyLeft(self):
        self.infoLabel.setText(
            "No energy left. Waiting until refill to play again.")

    def onEngineStateChanged(self, state: EngineState):
        if state == EngineState.Playing:
            self.infoLabel.setText("Engine started playing")
        elif state == EngineState.StopInvoked:
            self.infoLabel.setText("Engine stopping. Wait a second....")
        elif state == EngineState.Ready:
            self.infoLabel.setText("Engine is ready")

    def get_toolbar_size(self):
        return self.toolbar_w, self.toolbar_h

    def onConnectionStateChange(self, connected: bool):
        if connected:
            self.infoLabel.setText("Device found! Engine is ready")
            self.lblConnectionStatus.setText("Connected")
            self.lblConnectionStatus.setStyleSheet("color: white")
        else:
            self.infoLabel.setText("Waiting for a device to be connected")
            self.lblConnectionStatus.setText("NO device!")
            self.lblConnectionStatus.setStyleSheet(
                "background-color: red;color:white")

    def onCheckConnectionStateChanged(self, checking: bool):
        self.lblCheckConnectionStatus.setText(
            'connecting..' if checking else '')

    def onScreenDataChanged(self):
        self.size_info_lbl.setText("Device size:\n{}x{}".format(
            self.model.engine.width, self.model.engine.heigth))
        self.lblDataFolder.setText("{}".format(
            self.model.engine.currentDataFolder))

    def setupUi(self, main_window: QMainWindow):
        main_window.setObjectName("game_controller_window")
        self.setObjectName("main_window")
        self.resize(450, 620)
        self.setMinimumWidth(620)
        self.setMinimumHeight(450)
        self.main_layout.setSpacing(0)
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setColumnStretch(0, 0)
        self.main_layout.setRowStretch(0, 0)
        self.main_layout.setColumnStretch(1, 200)
        self.main_layout.setRowStretch(1, 200)
        self.setLayout(self.main_layout)

        self.main_layout.addWidget(self.dungeonSelector, 0, 0)
        lay_content = QVBoxLayout()
        self.toolbarOptions.addWidget(self.size_info_lbl)
        self.toolbarOptions.addWidget(self.lblConnectionStatus)
        self.toolbarOptions.addWidget(self.lblCheckConnectionStatus)

        self.cBoxhealStrategy.addItems(['Always power', 'Always heal'])
        self.lblInfoHealStrategy.setText('Healing Strategy:')
        self.toolbarOptions.addWidget(self.lblInfoHealStrategy)
        self.toolbarOptions.addWidget(self.cBoxhealStrategy)

        lay_content.addWidget(self.controlWidget)
        lay_content.addWidget(self.infoLabel)
        self.lblInfoHealStrategy.setStyleSheet(
            "background-color: #6e6e6e; color: white")
        self.cBoxhealStrategy.setStyleSheet(
            "background-color: #6e6e6e; color: white")
        self.controlWidget.setStyleSheet("background-color: #6e6e6e")
        self.size_info_lbl.setStyleSheet(
            "background-color: #6e6e6e; color: white")
        self.lblConnectionStatus.setStyleSheet(
            "background-color: #6e6e6e; color: white")
        self.lblCheckConnectionStatus.setStyleSheet("color: white")
        self.lblCheckConnectionStatus.setText('Starting...')
        self.lblDataFolder.setStyleSheet(
            "background-color: #6e6e6e; color: white")
        self.infoLabel.setStyleSheet("background-color: #6e6e6e; color: white")

        self.size_info_lbl.setAlignment(Qt.AlignCenter)
        self.infoLabel.setAlignment(Qt.AlignCenter)
        self.lblConnectionStatus.setAlignment(Qt.AlignCenter)
        self.lblCheckConnectionStatus.setAlignment(Qt.AlignCenter)
        lay_header = QHBoxLayout()
        lay_header.addLayout(lay_content, 20)
        lay_header.addWidget(self.currentLevelWidget, 1)
        self.main_layout.addLayout(lay_header, 0, 1)
        self.widActions.setFixedWidth(self.toolbar_w)
        self.main_layout.addLayout(self.toolbarOptions, 1, 0)
        self.toolbarOptions.setAlignment(Qt.AlignTop)
        self.toolbarOptions.setContentsMargins(5, 5, 5, 0)
        self.toolbarOptions.setSpacing(10)

        self.content_wid.setSizePolicy(
            QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                  QtWidgets.QSizePolicy.Expanding))
        # self.content_wid.setStyleSheet("background-color: rgb(43, 43, 43)")
        self.main_layout.addWidget(self.content_wid, 1, 1)
        self.setStyleSheet("background-color: #6e6e6e")
        main_window.setStyleSheet("background-color: #6e6e6e")
        self.setLayout(self.main_layout)
        main_window.setCentralWidget(self)

        self.onScreenDataChanged()  # To initialize
        self.onConnectionStateChange(self.model.connected())  # To initialize
Beispiel #33
0
class MainWindow(QMainWindow, Ui_MainWindow):
    '''
    classdocs
    '''

    def __init__(self, app):
        """
        Init
        :param cutecoin.core.app.Application app: application
        :type: cutecoin.core.app.Application
        """
        # Set up the user interface from Designer.
        super().__init__()
        self.setupUi(self)
        QApplication.setWindowIcon(QIcon(":/icons/cutecoin_logo"))
        self.app = app
        logging.debug(app.thread())
        logging.debug(self.thread())
        self.password_asker = None
        self.initialized = False

        self.busybar = QProgressBar(self.statusbar)
        self.busybar.setMinimum(0)
        self.busybar.setMaximum(0)
        self.busybar.setValue(-1)
        self.statusbar.addWidget(self.busybar)
        self.busybar.hide()
        self.app.version_requested.connect(self.latest_version_requested)
        self.app.get_last_version()

        self.combo_referential = QComboBox(self)
        self.combo_referential.setEnabled(False)
        self.combo_referential.currentIndexChanged.connect(self.referential_changed)

        self.status_label = QLabel("", self)
        self.status_label.setTextFormat(Qt.RichText)

        self.label_time = QLabel("", self)

        self.statusbar.addPermanentWidget(self.status_label, 1)
        self.statusbar.addPermanentWidget(self.label_time)
        self.statusbar.addPermanentWidget(self.combo_referential)
        self.update_time()

        self.loader = Loader(self.app)
        self.loader.loaded.connect(self.loader_finished)
        self.loader.connection_error.connect(self.display_error)

        self.homescreen = HomeScreenWidget(self.app)
        self.centralWidget().layout().addWidget(self.homescreen)
        self.homescreen.button_new.clicked.connect(self.open_add_account_dialog)
        self.homescreen.button_import.clicked.connect(self.import_account)
        self.open_ucoin_info = lambda: QDesktopServices.openUrl(QUrl("http://ucoin.io/theoretical/"))
        self.homescreen.button_info.clicked.connect(self.open_ucoin_info)

        self.import_dialog = None
        self.export_dialog = None

        # TODO: There are too much refresh() calls on startup
        self.refresh()

    def open_add_account_dialog(self):
        dialog = ProcessConfigureAccount(self.app, None)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.action_change_account(self.app.current_account.name)

    @pyqtSlot(str)
    def display_error(self, error):
        QMessageBox.critical(self, ":(",
                             error,
                             QMessageBox.Ok)

    @pyqtSlot(str)
    def referential_changed(self, index):
        if self.app.current_account:
            self.app.current_account.set_display_referential(index)
            if self.currencies_tabwidget.currentWidget():
                self.currencies_tabwidget.currentWidget().referential_changed()

    @pyqtSlot()
    def update_time(self):
        date = QDate.currentDate()
        self.label_time.setText("{0}".format(date.toString("dd/MM/yyyy")))
        next_day = date.addDays(1)
        current_time = QDateTime().currentDateTime().toMSecsSinceEpoch()
        next_time = QDateTime(next_day).toMSecsSinceEpoch()
        timer = QTimer()
        timer.timeout.connect(self.update_time)
        timer.start(next_time - current_time)

    @pyqtSlot()
    def delete_contact(self):
        contact = self.sender().data()
        self.app.current_account.contacts.remove(contact)
        self.refresh_contacts()

    @pyqtSlot()
    def edit_contact(self):
        index = self.sender().data()
        dialog = ConfigureContactDialog(self.app.current_account, self, None, index)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()

    def action_change_account(self, account_name):
        def loading_progressed(value, maximum):
            logging.debug("Busybar : {:} : {:}".format(value, maximum))
            self.busybar.setValue(value)
            self.busybar.setMaximum(maximum)
            QApplication.processEvents()

        if self.app.current_account:
            self.app.save_cache(self.app.current_account)

        self.app.current_account = None
        self.refresh()
        QApplication.setOverrideCursor(Qt.BusyCursor)
        self.app.loading_progressed.connect(loading_progressed)
        self.busybar.setMinimum(0)
        self.busybar.setMaximum(0)
        self.busybar.setValue(-1)
        self.busybar.show()
        self.status_label.setText(self.tr("Loading account {0}").format(account_name))
        self.loader.set_account_name(account_name)
        QTimer.singleShot(10, self.loader.load)
        self.homescreen.button_new.hide()
        self.homescreen.button_import.hide()

    @pyqtSlot()
    def loader_finished(self):
        logging.debug("Finished loading")
        self.refresh()
        self.busybar.hide()
        QApplication.setOverrideCursor(Qt.ArrowCursor)
        try:
            self.app.disconnect()
        except:
            logging.debug("Disconnect of app failed")

        self.app.monitor.start_network_watchers()
        QApplication.processEvents()

    def open_transfer_money_dialog(self):
        dialog = TransferMoneyDialog(self.app.current_account,
                                     self.password_asker)
        dialog.accepted.connect(self.refresh_wallets)
        if dialog.exec_() == QDialog.Accepted:
            currency_tab = self.currencies_tabwidget.currentWidget()
            currency_tab.tab_history.table_history.model().sourceModel().refresh_transfers()

    def open_certification_dialog(self):
        dialog = CertificationDialog(self.app.current_account,
                                     self.password_asker)
        dialog.exec_()

    def open_add_contact_dialog(self):
        dialog = ConfigureContactDialog(self.app.current_account, self)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.window().refresh_contacts()

    def open_configure_account_dialog(self):
        dialog = ProcessConfigureAccount(self.app, self.app.current_account)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            if self.app.current_account:
                self.action_change_account(self.app.current_account.name)
            else:
                self.refresh()

    def open_preferences_dialog(self):
        dialog = PreferencesDialog(self.app)
        result = dialog.exec_()

    def open_about_popup(self):
        """
        Open about popup window
        """
        aboutDialog = QDialog(self)
        aboutUi = Ui_AboutPopup()
        aboutUi.setupUi(aboutDialog)

        latest = self.app.available_version
        version_info = ""
        version_url = ""
        if not latest[0]:
            version_info = self.tr("Latest release : {version}") \
                .format(version=latest[1])
            version_url = latest[2]

            new_version_text = """
                <p><b>{version_info}</b></p>
                <p><a href="{version_url}">{link_text}</a></p>
                """.format(version_info=version_info,
                            version_url=version_url,
                            link_text=self.tr("Download link"))
        else:
            new_version_text = ""

        text = self.tr("""
        <h1>Cutecoin</h1>

        <p>Python/Qt uCoin client</p>

        <p>Version : {:}</p>
        {new_version_text}

        <p>License : MIT</p>

        <p><b>Authors</b></p>

        <p>inso</p>
        <p>vit</p>
        <p>canercandan</p>
        """).format(__version__, new_version_text=new_version_text)

        aboutUi.label.setText(text)
        aboutDialog.show()

    @pyqtSlot()
    def latest_version_requested(self):
        latest = self.app.available_version
        logging.debug("Latest version requested")
        if not latest[0]:
            version_info = self.tr("Please get the latest release {version}") \
                .format(version=latest[1])
            version_url = latest[2]

            toast.display("Cutecoin", """<p>{version_info}</br>
<a href={version_url}>Download link</a></p>""".format(
                version_info=version_info,
                version_url=version_url))

    def refresh_wallets(self):
        currency_tab = self.currencies_tabwidget.currentWidget()
        if currency_tab:
            currency_tab.refresh_wallets()

    def refresh_communities(self):
        logging.debug("CLEAR")
        self.currencies_tabwidget.clear()
        if self.app.current_account:
            for community in self.app.current_account.communities:
                tab_currency = CurrencyTabWidget(self.app, community,
                                                 self.password_asker,
                                                 self.status_label)
                tab_currency.refresh()
                self.currencies_tabwidget.addTab(tab_currency,
                                                 QIcon(":/icons/currency_icon"),
                                                 community.name)

    def refresh_accounts(self):
        self.menu_change_account.clear()
        signal_mapper = QSignalMapper(self)

        for account_name in sorted(self.app.accounts.keys()):
            action = QAction(account_name, self)
            self.menu_change_account.addAction(action)
            signal_mapper.setMapping(action, account_name)
            action.triggered.connect(signal_mapper.map)
            signal_mapper.mapped[str].connect(self.action_change_account)

    def refresh_contacts(self):
        self.menu_contacts_list.clear()
        if self.app.current_account:
            for index, contact in enumerate(self.app.current_account.contacts):
                contact_menu = self.menu_contacts_list.addMenu(contact['name'])
                edit_action = contact_menu.addAction(self.tr("Edit"))
                edit_action.triggered.connect(self.edit_contact)
                edit_action.setData(index)
                delete_action = contact_menu.addAction(self.tr("Delete"))
                delete_action.setData(contact)
                delete_action.triggered.connect(self.delete_contact)

    def refresh(self):
        '''
        Refresh main window
        When the selected account changes, all the widgets
        in the window have to be refreshed
        '''
        logging.debug("Refresh started")
        self.refresh_accounts()

        if self.app.current_account is None:
            self.currencies_tabwidget.hide()
            self.homescreen.show()
            self.setWindowTitle(self.tr("CuteCoin {0}").format(__version__))
            self.menu_account.setEnabled(False)
            self.action_configure_parameters.setEnabled(False)
            self.action_set_as_default.setEnabled(False)
            self.combo_referential.setEnabled(False)
            self.status_label.setText(self.tr(""))
            self.password_asker = None
        else:
            logging.debug("Show currencies loading")
            self.currencies_tabwidget.show()
            logging.debug("Hide homescreen")
            self.homescreen.hide()
            self.password_asker = PasswordAskerDialog(self.app.current_account)

            self.combo_referential.blockSignals(True)
            self.combo_referential.clear()
            for ref in self.app.current_account.referentials:
                self.combo_referential.addItem(QCoreApplication.translate('Account', ref[4]))

            self.combo_referential.setEnabled(True)
            self.combo_referential.blockSignals(False)
            logging.debug(self.app.preferences)
            self.combo_referential.setCurrentIndex(self.app.preferences['ref'])
            self.menu_account.setEnabled(True)
            self.action_configure_parameters.setEnabled(True)
            self.setWindowTitle(self.tr("CuteCoin {0} - Account : {1}").format(__version__,
                                                                               self.app.current_account.name))

        self.refresh_communities()
        self.refresh_wallets()
        self.refresh_contacts()

    def import_account(self):
        self.import_dialog = ImportAccountDialog(self.app, self)
        self.import_dialog.accepted.connect(self.import_account_accepted)
        self.import_dialog.exec_()

    def import_account_accepted(self):
        # open account after import
        self.action_change_account(self.import_dialog.edit_name.text())

    def export_account(self):
        # Testable way of using a QFileDialog
        self.export_dialog = QFileDialog(self)
        self.export_dialog.setObjectName('ExportFileDialog')
        self.export_dialog.setWindowTitle(self.tr("Export an account"))
        self.export_dialog.setNameFilter(self.tr("All account files (*.acc)"))
        self.export_dialog.setLabelText(QFileDialog.Accept, self.tr('Export'))
        self.export_dialog.accepted.connect(self.export_account_accepted)
        self.export_dialog.show()

    def export_account_accepted(self):
        selected_file = self.export_dialog.selectedFiles()
        if selected_file:
            if selected_file[0][-4:] == ".acc":
                path = selected_file[0]
            else:
                path = selected_file[0] + ".acc"
            self.app.export_account(path, self.app.current_account)

    def closeEvent(self, event):
        if self.app.current_account:
            self.app.save_cache(self.app.current_account)
        self.app.save_persons()
        super().closeEvent(event)

    def showEvent(self, event):
        super().showEvent(event)
        if not self.initialized:
            # if default account in preferences...
            if self.app.preferences['account'] != "":
                logging.debug("Loading default account")
                self.action_change_account(self.app.preferences['account'])
            # no default account...
            else:
                # if at least one account exists, set it as default...
                if len(self.app.accounts) > 0:
                    # capture names sorted alphabetically
                    names = list(self.app.accounts.keys())
                    names.sort()
                    # set first name in list as default in preferences
                    self.app.preferences['account'] = names[0]
                    self.app.save_preferences(self.app.preferences)
                    # open it
                    logging.debug("No default account in preferences. Set %s as default account." % names[0])
                    self.action_change_account(self.app.preferences['account'])

            self.initialized = True
Beispiel #34
0
class PropertyWidget(QWidget):

    value_changed = pyqtSignal(object)
    """display widget for tcam property"""
    def __init__(self,
                 data: TcamCaptureData,
                 prop: Prop,
                 app_property: bool = False):
        super().__init__()
        self.app_property = app_property
        self.tcam = data.tcam
        self.signals = data.signals
        self.prop = prop
        self.is_log = False
        self.setup_ui()

    def __repr__(self):
        return repr((self.prop.name, self.prop.valuetype, self.prop.category,
                     self.prop.group))

    def __setup_ui_boolean(self):
        """
        Helper function that contains all setup code for bool UIs
        """
        self.toggle = QCheckBox(self)
        self.toggle.setCheckable(True)
        if self.prop.value:
            self.toggle.toggle()
        self.toggle.toggled.connect(self.button_clicked)
        self.layout.addWidget(self.toggle)

    def __setup_ui_integer(self):
        """

        """

        self.value_box = TcamSpinBox.TcamSpinBox(self)
        try:
            self.value_box.setRange(self.prop.minval, self.prop.maxval)
        except OverflowError:
            log.error("Property {} reported a range "
                      "that could not be handled".format(self.prop.name))

        self.value_box.setSingleStep(self.prop.step)
        self.value_box.blockSignals(True)
        self.value_box.setValue(self.prop.value)
        self.value_box.blockSignals(False)
        self.value_box.valueChanged[int].connect(self.set_property_box)
        self.value_box.setKeyboardTracking(False)

        if self.is_log:
            log.debug("Adding log slider for {}".format(self.prop.name))
            self.sld = TcamSlider.TcamLogSlider(self)
            self.sld.valueLogChanged.connect(self.set_property)
        else:
            self.sld = TcamSlider.TcamSlider(self)
            self.sld.valueChanged[int].connect(self.set_property)

        self.sld.setFocusPolicy(Qt.NoFocus)
        try:
            self.sld.blockSignals(True)
            self.sld.setRange(self.prop.minval, self.prop.maxval)
            self.sld.setValue(self.prop.value)
            self.sld.blockSignals(False)

        except OverflowError:
            log.error("Property {} reported a range "
                      "that could not be handled".format(self.prop.name))
        self.sld.setSingleStep(self.prop.step)
        self.sld.doubleClicked.connect(self.reset)

        self.layout.addWidget(self.sld)
        self.layout.addWidget(self.value_box)

    def __setup_ui_double(self):
        """
        Helper function that contains all setup code for doube UIs
        """
        self.value_box = TcamSpinBox.TcamDoubleSpinBox(self)
        try:
            self.value_box.setRange(self.prop.minval, self.prop.maxval)
        except OverflowError:
            log.error("Property {} reported a range "
                      "that could not be handled".format(self.prop.name))

        self.value_box.setSingleStep(self.prop.step)
        self.value_box.blockSignals(True)
        self.value_box.setValue(self.prop.value)
        self.value_box.blockSignals(False)
        self.value_box.valueChanged[float].connect(self.set_property_box)
        self.value_box.setKeyboardTracking(False)

        if self.is_log:
            self.sld = TcamSlider.TcamLogSlider(self)
            self.sld.valueLogChanged.connect(self.set_property)
        else:
            self.sld = TcamSlider.TcamSlider(self)
            self.sld.valueChanged[int].connect(self.set_property)

        self.sld.setFocusPolicy(Qt.NoFocus)
        try:
            self.sld.blockSignals(True)
            self.sld.setRange(int(self.prop.minval * 100),
                              int(self.prop.maxval * 100))
            self.sld.setValue(int(self.prop.value * 100))
            self.sld.blockSignals(False)

        except OverflowError:
            log.warning("Property {} reported a range "
                        "that could not be handled min: {} max: {}".format(
                            self.prop.name, self.prop.minval,
                            self.prop.maxval))
        self.sld.setSingleStep(int(self.prop.step * 100))
        self.sld.doubleClicked.connect(self.reset)

        self.sld.setGeometry(30, 40, 100, 30)
        self.layout.addWidget(self.sld)
        self.layout.addWidget(self.value_box)

    def setup_ui(self):
        self.layout = QHBoxLayout()

        def should_be_logarithmic(prop):
            """
            Returns True when the range is > 5000
            """
            if prop.valuetype == "integer":
                if (prop.maxval - prop.minval) >= 5000:
                    return True

            elif prop.valuetype == "double":
                if (prop.maxval - prop.minval) >= 5000:
                    return True

            return False

        self.setLayout(self.layout)

        self.is_log = should_be_logarithmic(self.prop)

        if self.prop.valuetype == "integer":

            self.__setup_ui_integer()

        elif self.prop.valuetype == "double":

            self.__setup_ui_double()

        elif self.prop.valuetype == "button":
            self.checkbox = QPushButton(self)
            self.checkbox.clicked.connect(self.set_property)
            self.layout.addWidget(self.checkbox)

        elif self.prop.valuetype == "boolean":
            self.__setup_ui_boolean()

        elif self.prop.valuetype == "string":
            pass

        elif self.prop.valuetype == "enum":
            self.combo = QComboBox(self)
            entry_list = self.tcam.get_tcam_menu_entries(self.prop.name)

            for e in entry_list:
                self.combo.addItem(e)
                self.combo.setCurrentText(self.prop.value)
                self.combo.currentIndexChanged['QString'].connect(
                    self.set_property)
                self.layout.addWidget(self.combo)

    def button_clicked(self):
        log.debug("button clicked")
        self.signals.change_property.emit(self.tcam, self.prop.name,
                                          self.toggle.isChecked(),
                                          self.prop.valuetype)
        self.value_changed.emit(self)

    def set_property(self, value, emit_value_changed=True):
        self.prop.value = value
        if self.prop.valuetype == "integer":
            self.update_box_value(self.value_box, value)

        if self.prop.valuetype == "double":
            self.update_box_value(self.value_box, value / 100)

            self.signals.change_property.emit(self.tcam, self.prop.name,
                                              float(value / 100),
                                              self.prop.valuetype)
            return

        self.signals.change_property.emit(self.tcam, self.prop.name, value,
                                          self.prop.valuetype)
        if emit_value_changed:
            self.value_changed.emit(self)

    def set_property_box(self, value):
        if self.prop.valuetype == "integer":
            self.update_slider_value(self.sld, value)

        if self.prop.valuetype == "double":
            self.update_slider_value(self.sld, value)

            self.signals.change_property.emit(self.tcam, self.prop.name,
                                              float(value),
                                              self.prop.valuetype)
            return

        self.signals.change_property.emit(self.tcam, self.prop.name, value,
                                          self.prop.valuetype)
        self.value_changed.emit(self)

    def update_box_value(self, box, value):
        box.blockSignals(True)
        box.setValue(value)
        box.blockSignals(False)

    def update_box_range(self, box, minval, maxval):
        """"""
        box.blockSignals(True)
        box.setRange(self.prop.minval, self.prop.maxval)
        box.blockSignals(False)

    def update_slider_value(self, slider, value):
        slider.blockSignals(True)
        try:
            if self.prop.valuetype == "double":
                slider.setValue(int(value * 100))
            else:
                slider.setValue(value)

        except OverflowError:
            log.info("The slider for '{}' had a value outside of the integer "
                     "range. That should no happen.".format(self.prop.name))
        finally:
            slider.blockSignals(False)

    def update_slider_range(self, slider, minval, maxval):
        """"""
        self.sld.blockSignals(True)
        try:
            if self.prop.valuetype == "double":
                self.sld.setRange(self.prop.minval * 100,
                                  self.prop.maxval * 100)
            else:
                self.sld.setRange(self.prop.minval, self.prop.maxval)
        except OverflowError:
            log.error("The slider for '{}' had a value outside of the integer "
                      "range. That should no happen. "
                      "Min: '{}' Max: {}".format(self.prop.name,
                                                 self.prop.minval,
                                                 self.prop.maxval))
        finally:
            self.sld.blockSignals(False)

    def update(self, prop: Prop):

        emit_value_changed = False

        if self.prop.value != prop.value:
            emit_value_changed = True

        self.prop = prop
        if self.prop.valuetype == "integer":
            if type(self.value_box) is TcamSpinBox.TcamSpinBox:
                if self.value_box.active():
                    # box.setValue(value)
                    return
            self.update_slider_value(self.sld, self.prop.value)

            self.update_slider_range(self.sld, self.prop.minval,
                                     self.prop.maxval)
            self.update_box_range(self.value_box, self.prop.minval,
                                  self.prop.maxval)
            self.update_box_value(self.value_box, self.prop.value)
        elif self.prop.valuetype == "double":
            self.update_slider_range(self.sld, self.prop.minval,
                                     self.prop.maxval)
            self.update_slider_value(self.sld, self.prop.value)
            self.update_box_range(self.value_box, self.prop.minval,
                                  self.prop.maxval)
            self.update_box_value(self.value_box, self.prop.value)

        elif self.prop.valuetype == "button":
            pass

        elif self.prop.valuetype == "boolean":

            if self.prop.value and not self.toggle.isChecked():
                self.toggle.blockSignals(True)
                self.toggle.toggle()
                self.toggle.blockSignals(False)

        elif self.prop.valuetype == "string":
            pass
        elif self.prop.valuetype == "enum":
            self.combo.blockSignals(True)
            self.combo.setCurrentText(prop.value)
            self.combo.blockSignals(False)

        if emit_value_changed:
            self.value_changed.emit(self)

    def reset(self):
        if self.prop.valuetype == "integer":
            self.update_box_value(self.value_box, self.prop.defval)
            self.update_slider_value(self.sld, self.prop.defval)

        elif self.prop.valuetype == "double":
            self.update_box_value(self.value_box, self.prop.defval)
            self.update_slider_value(self.sld, self.prop.defval)

        elif self.prop.valuetype == "button":
            pass

        elif self.prop.valuetype == "boolean":
            if self.prop.defval and not self.toggle.isChecked():
                self.toggle.toggle()

        elif self.prop.valuetype == "string":
            pass
        elif self.prop.valuetype == "enum":
            self.combo.setCurrentText(self.prop.defval)
        self.value_changed.emit(self)
        self.signals.change_property.emit(self.tcam, self.prop.name,
                                          self.prop.defval,
                                          self.prop.valuetype)
Beispiel #35
0
class MetricsToolBar(QToolBar):
    """
    Emits *pointSizeChanged*.
    """
    glyphsChanged = pyqtSignal(list)
    settingsChanged = pyqtSignal(dict)

    def __init__(self, font, parent=None):
        super().__init__(parent)
        auxiliaryWidth = self.fontMetrics().width('0') * 8
        self.leftTextField = MetricsSequenceEdit(font, self)
        self.leftTextField.setMaximumWidth(auxiliaryWidth)
        self.textField = MetricsSequenceComboBox(font, self)
        # XXX: had to use Maximum because Preferred did extend the widget(?)
        self.textField.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Maximum)
        self.rightTextField = MetricsSequenceEdit(font, self)
        self.rightTextField.setMaximumWidth(auxiliaryWidth)
        self.leftTextField.textEdited.connect(self.textField.editTextChanged)
        self.rightTextField.textEdited.connect(self.textField.editTextChanged)
        self.textField.editTextChanged.connect(self._textChanged)

        self.comboBox = QComboBox(self)
        self.comboBox.setEditable(True)
        self.comboBox.setCompleter(None)
        self.comboBox.setValidator(QIntValidator(self))
        for p in pointSizes:
            self.comboBox.addItem(str(p))
        self.pointSizeChanged = self.comboBox.currentIndexChanged[str]

        self.configBar = QPushButton(self)
        self.configBar.setFlat(True)
        self.configBar.setIcon(QIcon(":settings.svg"))
        self.configBar.setStyleSheet("padding: 2px 0px; padding-right: 10px")
        self.toolsMenu = QMenu(self)
        self._showKerning = self.toolsMenu.addAction(
            self.tr("Show Kerning"), self._kerningVisibilityChanged)
        self._showKerning.setCheckable(True)
        self._showMetrics = self.toolsMenu.addAction(
            self.tr("Show Metrics"), self._controlsTriggered)
        self._showMetrics.setCheckable(True)
        self.toolsMenu.addSeparator()
        self._verticalFlip = self.toolsMenu.addAction(
            self.tr("Vertical Flip"), self._controlsTriggered)
        self._verticalFlip.setCheckable(True)
        self._wrapLines = self.toolsMenu.addAction(
            self.tr("Wrap Lines"), self._controlsTriggered)
        self._wrapLines.setCheckable(True)
        self.toolsMenu.addSeparator()
        action = self.toolsMenu.addAction(self.tr("Line Height:"))
        action.setEnabled(False)
        lineHeight = QWidgetAction(self.toolsMenu)
        self._lineHeightSlider = slider = QSlider(Qt.Horizontal, self)
        # QSlider works with integers so we'll just divide what comes out of it
        # by 100
        slider.setMinimum(80)
        slider.setMaximum(160)
        slider.setValue(110)
        slider.valueChanged.connect(self._controlsTriggered)
        slider.valueChanged.connect(self._sliderLineHeightChanged)
        lineHeight.setDefaultWidget(slider)
        self.toolsMenu.addAction(lineHeight)
        self.configBar.setMenu(self.toolsMenu)

        self.addWidget(self.leftTextField)
        self.addWidget(self.textField)
        self.addWidget(self.rightTextField)
        self.addWidget(self.comboBox)
        self.addWidget(self.configBar)

        app = QApplication.instance()
        app.dispatcher.addObserver(
            self, "_currentGlyphChanged", "currentGlyphChanged")

        self.readSettings()

    def readSettings(self):
        items = settings.metricsWindowComboBoxItems()
        self.textField.clear()
        self.textField.addItems(items)

    # -------------
    # Notifications
    # -------------

    # app

    def _currentGlyphChanged(self, notification):
        self._textChanged()

    # widget

    def _controlsTriggered(self):
        params = dict(
            lineHeight=self._lineHeightSlider.value() / 100,
            showKerning=self._showKerning.isChecked(),
            showMetrics=self._showMetrics.isChecked(),
            verticalFlip=self._verticalFlip.isChecked(),
            wrapLines=self._wrapLines.isChecked(),
        )
        self.settingsChanged.emit(params)

    def _kerningVisibilityChanged(self):
        self._controlsTriggered()
        # if showKerning was triggered, it won't apply until we pipe the glyphs
        # again. do so
        self._textChanged()

    def _sliderLineHeightChanged(self, value):
        QToolTip.showText(QCursor.pos(), str(value / 100), self)

    def _textChanged(self):
        leftGlyphs = self.leftTextField.glyphs()
        rightGlyphs = self.rightTextField.glyphs()
        glyphs = self.textField.glyphs()
        ret = []
        for glyph in glyphs:
            ret.extend(leftGlyphs + [glyph] + rightGlyphs)
        self.glyphsChanged.emit(ret)

    # --------------
    # Public methods
    # --------------

    def setPointSize(self, pointSize):
        self.comboBox.blockSignals(True)
        self.comboBox.setEditText(str(pointSize))
        self.comboBox.blockSignals(False)

    def setText(self, text, left=None, right=None):
        self.leftTextField.setText(left)
        self.rightTextField.setText(right)
        self.textField.setEditText(text)

    def setWrapLines(self, value):
        self._wrapLines.setChecked(value)
        self._controlsTriggered()

    # TODO: more methods

    # ----------
    # Qt methods
    # ----------

    def closeEvent(self, event):
        super().closeEvent(event)
        if event.isAccepted():
            app = QApplication.instance()
            app.dispatcher.removeObserver(self, "currentGlyphChanged")

    def showEvent(self, event):
        super().showEvent(event)
        self.textField.setFocus(True)
Beispiel #36
0
class DataManager(QWidget):

    wldsetChanged = QSignal(object)
    wxdsetChanged = QSignal(object)
    sig_workdir_changed = QSignal(str)
    sig_new_console_msg = QSignal(str)

    def __init__(self, parent=None, projet=None, pm=None, pytesting=False):
        super(DataManager, self).__init__(parent)
        self._pytesting = pytesting
        self._projet = projet
        self._confirm_before_deleting_dset = True

        self._wldset = None
        self._wxdset = None

        self.setWindowFlags(Qt.Window)
        self.setWindowIcon(icons.get_icon('master'))
        self.setMinimumWidth(250)

        self.weather_avg_graph = None

        self.new_waterlvl_win = NewDatasetDialog('water level', parent, projet)
        self.new_waterlvl_win.sig_new_dataset_imported.connect(
            self.new_wldset_imported)

        self.new_weather_win = NewDatasetDialog('daily weather', parent,
                                                projet)
        self.new_weather_win.sig_new_dataset_imported.connect(
            self.new_wxdset_imported)

        self.setup_manager()

        self.set_projet(projet)
        if pm:
            pm.currentProjetChanged.connect(self.set_projet)
            self.set_projet(pm.projet)

    def setup_manager(self):
        """Setup the layout of the manager."""
        layout = QGridLayout(self)
        layout.setSpacing(5)
        layout.setContentsMargins(0, 0, 0, 0)

        layout.addWidget(self.setup_wldset_mngr(), 0, 0)
        layout.addWidget(self.setup_wxdset_mngr(), 2, 0)

    def setup_wldset_mngr(self):
        """Setup the manager for the water level datasets."""

        # ---- Toolbar

        self.wldsets_cbox = QComboBox()
        self.wldsets_cbox.currentIndexChanged.connect(self.wldset_changed)

        self.btn_load_wl = QToolButtonSmall(icons.get_icon('importFile'))
        self.btn_load_wl.setToolTip('Import a new water level dataset...')
        self.btn_load_wl.clicked.connect(self.import_wldataset)

        self.btn_del_wldset = QToolButtonSmall('delete_data')
        self.btn_del_wldset.setToolTip('Delete current dataset.')
        self.btn_del_wldset.clicked.connect(self.del_current_wldset)

        wl_toolbar = ToolBarWidget()
        for widg in [self.btn_load_wl, self.btn_del_wldset]:
            wl_toolbar.addWidget(widg)

        # ---- Info Box

        self.well_info_widget = StrSpinBox()

        # ---- Main Layout

        grpbox = QGroupBox('Water Level Dataset : ')
        layout = QGridLayout(grpbox)
        layout.setSpacing(5)

        layout.addWidget(self.wldsets_cbox, 1, 0)
        layout.addWidget(self.well_info_widget, 2, 0)
        layout.addWidget(wl_toolbar, 3, 0)

        return grpbox

    def setup_wxdset_mngr(self):
        """Setup the manager for the weather datasets."""

        # ---- Toolbar

        self.wxdsets_cbox = QComboBox()
        self.wxdsets_cbox.currentIndexChanged.connect(self.wxdset_changed)

        self.btn_load_meteo = QToolButtonSmall(icons.get_icon('importFile'))
        self.btn_load_meteo.setToolTip('Import a new weather dataset...')
        self.btn_load_meteo.clicked.connect(self.import_wxdataset)

        self.btn_del_wxdset = QToolButtonSmall('delete_data')
        self.btn_del_wxdset.setToolTip('Delete current dataset.')
        self.btn_del_wxdset.clicked.connect(self.del_current_wxdset)

        btn_closest_meteo = QToolButtonSmall(icons.get_icon('closest_meteo'))
        btn_closest_meteo.setToolTip('<p>Select the weather station closest'
                                     ' from the observation well.</p>')
        btn_closest_meteo.clicked.connect(self.set_closest_wxdset)

        btn_weather_normals = QToolButtonSmall(icons.get_icon('meteo'))
        btn_weather_normals.setToolTip(
            "Show the normals for the current weather dataset.")
        btn_weather_normals.clicked.connect(self.show_weather_normals)

        self.btn_export_weather = ExportWeatherButton(workdir=self.workdir)
        self.btn_export_weather.setIconSize(icons.get_iconsize('small'))

        wx_toolbar = ToolBarWidget()
        for widg in [
                self.btn_load_meteo, self.btn_del_wxdset, btn_closest_meteo,
                btn_weather_normals, self.btn_export_weather
        ]:
            wx_toolbar.addWidget(widg)

        # ---- Info Box

        self.meteo_info_widget = StrSpinBox()

        # ---- Main Layout

        grpbox = QGroupBox('Weather Dataset : ')
        layout = QGridLayout(grpbox)
        layout.setSpacing(5)

        layout.addWidget(self.wxdsets_cbox, 1, 0)
        layout.addWidget(self.meteo_info_widget, 2, 0)
        layout.addWidget(wx_toolbar, 3, 0)

        return grpbox

    @property
    def workdir(self):
        """Return the path where the project hdf5 file is saved."""
        if self.projet is None:
            return osp.dirname(os.getcwd())
        else:
            return osp.dirname(self.projet.filename)

    @property
    def projet(self):
        """Return the projet object."""
        return self._projet

    def set_projet(self, projet):
        """Set the namespace for the projet hdf5 file."""
        self._projet = projet
        self._wldset = None
        self._wxdset = None
        if projet is not None:
            self.update_wldsets(projet.get_last_opened_wldset())
            self.update_wxdsets(projet.get_last_opened_wxdset())
            self.wldset_changed()

        self.btn_export_weather.set_model(self.get_current_wxdset())
        self.btn_export_weather.set_workdir(self.workdir)

        self.new_waterlvl_win.set_projet(projet)
        self.new_weather_win.set_projet(projet)

        self.sig_workdir_changed.emit(self.workdir)

    # ---- Utilities

    def emit_warning(self, msg):
        btn = QMessageBox.Ok
        QMessageBox.warning(self, 'Warning', msg, btn)

    def confirm_del_dataset(self, dsetname, dsettype):
        """
        Show a message box asking the user confirmation before deleting
        a dataset. Return the user's answer and whether the
        'do not show this message again' checkbox has been checked or not.
        """
        msg_box = QMessageBox(
            QMessageBox.Question,
            "Delete {} dataset '{}'".format(dsettype, dsetname),
            ("Do you want to delete the {} dataset <i>{}</i>?<br><br>"
             "All data will be deleted from the project, but the "
             "original data files will be preserved.<br>").format(
                 dsettype, dsetname),
            buttons=QMessageBox.Yes | QMessageBox.Cancel,
            parent=self)
        checkbox = QCheckBox("Don't show this message again.")
        msg_box.setCheckBox(checkbox)

        reply = msg_box.exec_()
        return reply, not checkbox.isChecked()

    # ---- WL Dataset
    @property
    def wldsets(self):
        """Return a list of all the wldset saved in the project."""
        return [] if self.projet is None else self.projet.wldsets

    def wldataset_count(self):
        """Return the total number of wldset saved in the project."""
        return len(self.wldsets)

    def import_wldataset(self):
        """Open a dialog window to import a water level dataset from a file."""
        if self.projet is None:
            msg = ("Please first select a valid project or create a new one.")
            btn = QMessageBox.Ok
            QMessageBox.warning(self, 'Create dataset', msg, btn)
            return
        else:
            if self._pytesting:
                self.new_waterlvl_win.show()
            else:
                self.new_waterlvl_win.exec_()

    def new_wldset_imported(self, name, dataset):
        """
        Receives the new water level dataset, saves it in the project and
        update the GUI.
        """
        print("Saving the new water level dataset in the project...", end=" ")
        self.projet.add_wldset(name, dataset)
        self.update_wldsets(name)
        self.wldset_changed()
        print("done")

    def update_wldsets(self, name=None):
        self.wldsets_cbox.blockSignals(True)
        self.wldsets_cbox.clear()
        self.wldsets_cbox.addItems(self.projet.wldsets)
        if name:
            self.wldsets_cbox.setCurrentIndex(self.wldsets_cbox.findText(name))
        self.wldsets_cbox.blockSignals(False)

    def update_wldset_info(self):
        """Update the infos of the wldset."""
        wldset = self.get_current_wldset()
        if wldset is not None:
            model = [
                "Well : %s" % wldset['Well'],
                "Well ID : %s" % wldset['Well ID'],
                "Latitude : %0.3f°" % wldset['Latitude'],
                "Longitude : %0.3f°" % wldset['Longitude'],
                "Elevation : %0.1f m" % wldset['Elevation'],
                "Municipality : %s" % wldset['Municipality'],
                "Province : %s" % wldset['Province']
            ]
        else:
            model = None
        self.well_info_widget.set_model(model)

    def wldset_changed(self):
        """Handle when the currently selected water level dataset changed."""
        QApplication.processEvents()
        self.update_wldset_info()
        self.wldsetChanged.emit(self.get_current_wldset())

    def get_current_wldset(self):
        """Return the currently selected water level dataset."""
        if self.wldsets_cbox.currentIndex() == -1:
            self._wldset = None
        else:
            cbox_text = self.wldsets_cbox.currentText()
            if self._wldset is None or self._wldset.name != cbox_text:
                self._wldset = self.projet.get_wldset(cbox_text)
        return self._wldset

    def set_current_wldset(self, name):
        """Set the current water level from its name."""
        self.wldsets_cbox.blockSignals(True)
        self.wldsets_cbox.setCurrentIndex(self.wldsets_cbox.findText(name))
        self.wldsets_cbox.blockSignals(False)
        self.wldset_changed()

    def del_current_wldset(self):
        """Delete the currently selected water level dataset."""
        if self.wldsets_cbox.count() > 0:
            dsetname = self.wldsets_cbox.currentText()
            if self._confirm_before_deleting_dset:
                reply, dont_show_again = self.confirm_del_dataset(
                    dsetname, 'water level')
                if reply == QMessageBox.Cancel:
                    return
                elif reply == QMessageBox.Yes:
                    self._confirm_before_deleting_dset = dont_show_again
            self._wldset = None
            self.projet.del_wldset(dsetname)
            self.update_wldsets()
            self.wldset_changed()
            self.sig_new_console_msg.emit(
                ("<font color=black>Water level dataset <i>{}</i> deleted "
                 "successfully.</font>").format(dsetname))

    # ---- WX Dataset
    @property
    def wxdsets(self):
        """Return a list of all the weather datasets saved in the project."""
        return [] if self.projet is None else self.projet.wxdsets

    def wxdataset_count(self):
        """Return the total number of weather datasets saved in the project."""
        return len(self.wxdsets)

    def import_wxdataset(self):
        """Open a dialog window to import a weather dataset from a file."""
        if self.projet is None:
            msg = ("Please first select a valid project or create a new one.")
            btn = QMessageBox.Ok
            QMessageBox.warning(self, 'Create dataset', msg, btn)
            return
        else:
            if self._pytesting:
                self.new_weather_win.show()
            else:
                self.new_weather_win.exec_()

    def new_wxdset_imported(self, name, dataset):
        """
        Receive the new weather dataset, save it in the project and
        update the GUI.
        """
        print("Saving the new weather dataset in the project.", end=" ")
        self.projet.add_wxdset(name, dataset)
        self.update_wxdsets(name)
        self.wxdset_changed()
        print("done")

    def update_wxdsets(self, name=None, silent=False):
        self.wxdsets_cbox.blockSignals(True)
        self.wxdsets_cbox.clear()
        self.wxdsets_cbox.addItems(self.projet.wxdsets)
        if name:
            self.wxdsets_cbox.setCurrentIndex(self.wxdsets_cbox.findText(name))
        self.wxdsets_cbox.blockSignals(False)

    def update_wxdset_info(self):
        """Update the infos of the wxdset."""
        wxdset = self.get_current_wxdset()
        if wxdset is not None:
            model = [
                "Station : %s" % wxdset.metadata['Station Name'],
                "Station ID : %s" % wxdset.metadata['Station ID'],
                "Latitude : %0.3f°" % wxdset.metadata['Latitude'],
                "Longitude : %0.3f°" % wxdset.metadata['Longitude'],
                "Elevation : %0.1f m" % wxdset.metadata['Elevation'],
                "Location : %s" % wxdset.metadata['Location']
            ]
        else:
            model = None
        self.meteo_info_widget.set_model(model)

    def wxdset_changed(self):
        """Handle when the currently selected weather dataset changed."""
        QApplication.processEvents()
        self.update_wxdset_info()
        self.btn_export_weather.set_model(self.get_current_wxdset())
        self.wxdsetChanged.emit(self.get_current_wxdset())

    def del_current_wxdset(self):
        """Delete the currently selected weather dataset."""
        if self.wxdsets_cbox.count() > 0:
            dsetname = self.wxdsets_cbox.currentText()
            if self._confirm_before_deleting_dset:
                reply, dont_show_again = self.confirm_del_dataset(
                    dsetname, 'weather')
                if reply == QMessageBox.Cancel:
                    return
                elif reply == QMessageBox.Yes:
                    self._confirm_before_deleting_dset = dont_show_again
            self._wxdset = None
            self.projet.del_wxdset(dsetname)
            self.update_wxdsets()
            self.wxdset_changed()
            self.sig_new_console_msg.emit(
                ("<font color=black>Weather dataset <i>{}</i> deleted "
                 "successfully.</font>").format(dsetname))

    def get_current_wxdset(self):
        """Return the currently selected weather dataset dataframe."""
        if self.wxdsets_cbox.currentIndex() == -1:
            self._wxdset = None
        else:
            cbox_text = self.wxdsets_cbox.currentText()
            if self._wxdset is None or self._wxdset.name != cbox_text:
                self._wxdset = self.projet.get_wxdset(cbox_text)
        return self._wxdset

    def set_current_wxdset(self, name):
        """Set the current weather dataset from its name."""
        self.wxdsets_cbox.blockSignals(True)
        self.wxdsets_cbox.setCurrentIndex(self.wxdsets_cbox.findText(name))
        self.wxdsets_cbox.blockSignals(False)
        self.wxdset_changed()

    def set_closest_wxdset(self):
        """
        Set the weather dataset of the station that is closest to the
        groundwater observation well.
        """
        if self._wldset is None or self.wxdataset_count() == 0:
            return None

        dist = calc_dist_from_coord(self._wldset['Latitude'],
                                    self._wldset['Longitude'],
                                    self.projet.get_wxdsets_lat(),
                                    self.projet.get_wxdsets_lon())
        closest_station = self.wxdsets[np.argmin(dist)]
        self.set_current_wxdset(closest_station)
        return closest_station

    def show_weather_normals(self):
        """Show the weather normals for the current weather dataset."""
        if self.get_current_wxdset() is None:
            return
        if self.weather_avg_graph is None:
            self.weather_avg_graph = WeatherViewer()

        self.weather_avg_graph.set_workdir(self.workdir)
        self.weather_avg_graph.set_weather_dataset(self.get_current_wxdset())
        self.weather_avg_graph.show()
Beispiel #37
0
class SelectDialog(QWidget):
    """
    Show a message box with an input field.

    Inherits:
    QDialog

    Signals:
    None
    """
    sig_start = pyqtSignal(object)
    sig_new_config = pyqtSignal(str, str)

    def __init__(self, *args, parent=None, **kwargs):
        """
        Initialise layout of the widget.

        Arguments:
        regex - Regularexpression to analyse
        parent - Parent widget

        Returns:
        None
        """
        super(SelectDialog, self).__init__(parent)
        self.columns = 10
        self.settings = None
        self.content = []
        self.widgets_dict = {}
        self.widgets = []
        self.neutral_name = 'neutral'
        self.bad_name = 'bad'
        self.good_name = 'good'
        self.input_name = 'input_files'
        self.model_name = 'model.h5'
        self.config_name = 'config.json'
        self.default_project_name = 'Project'
        self.model_out = None
        self.config_out = None
        self.current_index = 0
        self.layouts = {}
        self.labels = {}
        self.button_dict = {}

        self.current_model = None

        self.log_folder = None
        self.good_folder = None
        self.bad_folder = None
        self.classes_folder = None
        self.settings_file = None
        self.e2proc2d_exec = None
        self.sp_cinderella_train_exec = None
        self.sp_cinderella_predict_exec = None
        self.set_enable = None

        layout = QVBoxLayout(self)
        layout_h0 = QHBoxLayout()
        layout.addLayout(layout_h0)
        layout_h1 = QHBoxLayout()
        layout.addLayout(layout_h1)
        layout_h2 = QHBoxLayout()
        layout.addLayout(layout_h2)
        layout_h3 = QHBoxLayout()
        layout.addLayout(layout_h3)

        btn_done = QPushButton('Retrain', self)
        btn_done.clicked.connect(self.retrain)
        layout_h3.addWidget(btn_done)
        self.content.append(btn_done)

        layout_h3.addStretch(1)

        label_threshold = QLabel('Threshold', self)
        layout_h3.addWidget(label_threshold)
        self.content.append(label_threshold)

        self.threshold_repick = QLineEdit('0.5', self)
        layout_h3.addWidget(self.threshold_repick)
        self.content.append(self.threshold_repick)

        self.button_repick = QPushButton('Repick', self)
        self.button_repick.clicked.connect(self.repick)
        layout_h3.addWidget(self.button_repick)
        self.content.append(self.button_repick)

        btn = QPushButton('Set', self)
        btn.clicked.connect(self.set_settings)
        layout_h3.addWidget(btn)
        self.content.append(btn)

        self.edit = QLineEdit(str(self.columns), self)
        self.edit.editingFinished.connect(self.adjust_all_layouts)
        layout_h0.addWidget(QLabel('Columns:', self))
        layout_h0.addWidget(self.edit)
        self.content.append(self.edit)

        self.combo_text = QComboBox(self)
        self.combo_text.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self.combo_text.currentTextChanged.connect(self.set_current_folder)
        layout_h0.addWidget(self.combo_text)
        self.content.append(self.combo_text)

        self.btn_update = QPushButton('Update', self)
        self.btn_update.clicked.connect(self.start_retrain)
        layout_h0.addWidget(self.btn_update)
        self.content.append(self.btn_update)

        self.prefer_isac_checkbox = QCheckBox('Prefer ISAC', self)
        self.prefer_isac_checkbox.setToolTip(
            'If Project is selected, prefer ISAC over Cinderella runs. This will put all classes in the neutral position'
        )
        layout_h0.addWidget(self.prefer_isac_checkbox)
        self.content.append(self.prefer_isac_checkbox)

        for current_name in (self.good_name, self.neutral_name, self.bad_name):
            self.labels[current_name] = QLabel(current_name, self)
            self.widgets_dict[current_name] = []
            layout_h1.addWidget(self.labels[current_name])

            widget = QWidget(self)
            scroll_area = QScrollArea(self)
            scroll_area.setWidgetResizable(True)
            scroll_area.setWidget(widget)
            scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
            scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

            self.layouts[current_name] = QVBoxLayout(widget)
            self.layouts[current_name].setSpacing(2)
            self.layouts[current_name].addStretch(1)
            layout_h2.addWidget(scroll_area)

        self.sig_start.connect(self.start_retrain)
        self.adjust_all_layouts()
        self.enable(False)

    @pyqtSlot()
    def set_settings(self):
        try:
            name, threshold = self.combo_text.currentText().rsplit('_', 1)
        except ValueError:
            tu.message('Please provide a repicking run and not {}.'.format(
                self.default_project_name))
            return
        model = os.path.join(self.log_folder, name, self.model_name)
        self.sig_new_config.emit(model, threshold)
        tu.message('Set model: {}\nSet threshold: {}'.format(model, threshold))

    def enable(self, var, use_all=None):
        if not self.set_enable and var and self.set_enable is not None:
            var = False
        for entry in self.content:
            entry.setEnabled(var)

        if var:
            var = False
            if self.combo_text.currentText() == self.default_project_name:
                var = True
            self.btn_update.setEnabled(var)
            self.prefer_isac_checkbox.setEnabled(var)

    @pyqtSlot(str)
    @pyqtSlot()
    def set_current_folder(self, text=None):
        if text is None:
            text = self.combo_text.currentText()

        var = False
        if text == self.default_project_name:
            var = True
        self.btn_update.setEnabled(var)
        self.prefer_isac_checkbox.setEnabled(var)
        self.start_retrain(input_folder=text)

    def add_combo_item(self, items):
        current_items = [
            self.combo_text.itemText(idx)
            for idx in range(self.combo_text.count())
        ]
        current_items.extend(items)
        prev_state = self.combo_text.blockSignals(True)
        self.combo_text.clear()
        self.combo_text.addItems(sorted(list(set(current_items))))
        self.combo_text.blockSignals(prev_state)

    @pyqtSlot(object)
    @pyqtSlot()
    def start_retrain(self, settings=None, input_folder=None):
        if settings is not None:
            self.settings = settings
            file_names = [
                os.path.basename(entry) for entry in glob.glob(
                    os.path.join(self.settings['log_folder'], 'Retrain',
                                 'RUN_*.*'))
            ]
            self.add_combo_item([self.default_project_name])
            self.add_combo_item(file_names)
        self.clear()
        self.project_folder = self.settings['project_folder']
        self.log_folder = os.path.join(self.settings['log_folder'], 'Retrain')
        self.classes_folder = os.path.join(self.log_folder, 'RUN_{0}')
        self.model_out = os.path.join(self.classes_folder, self.model_name)
        self.config_out = os.path.join(self.classes_folder, self.config_name)

        self.good_folder = os.path.join(self.classes_folder, self.good_name)
        self.bad_folder = os.path.join(self.classes_folder, self.bad_name)

        self.settings_file = os.path.join(self.log_folder, 'tmp_settings.json')
        self.e2proc2d_exec = self.settings['Path']['e2proc2d.py']
        self.sp_cinderella_train_exec = self.settings['Path'][
            'sp_cinderella_train.py']
        try:
            self.sp_cinderella_predict_exec = self.settings['Path'][
                self.settings['Copy']['Select2d']]
        except KeyError:
            print(
                'In order to use the retrain tool, please provide a program in Copy->Select2d and press: Monitor Start -> Monitor Stop'
            )
            self.set_enable = False
            return
        else:
            self.set_enable = True

        for folder_name in (self.log_folder, ):
            tu.mkdir_p(folder_name)

        class_2d_folder = []
        select_2d_folder = []
        if input_folder is None or input_folder == self.default_project_name:
            for key in self.settings:
                if key.startswith('scratch_'):
                    continue
                if 'class2d' in key.lower():
                    try:
                        class_2d_folder.extend([
                            entry for entry in glob.glob(
                                os.path.join(
                                    self.settings[key],
                                    '*',
                                ))
                            if os.path.isdir(entry) and not os.path.basename(
                                entry).startswith('jpg') and not os.path.
                            basename(entry).startswith('overview_plots')
                        ])
                    except IndexError:
                        pass
                elif 'select2d' in key.lower():
                    try:
                        select_2d_folder.extend([
                            entry for entry in glob.glob(
                                os.path.join(
                                    self.settings[key],
                                    '*',
                                ))
                            if os.path.isdir(entry) and not os.path.basename(
                                entry).startswith('jpg') and not os.path.
                            basename(entry).startswith('overview_plots')
                        ])
                    except IndexError:
                        pass

            if self.prefer_isac_checkbox.isChecked():
                select_basenames = tuple(
                    [os.path.basename(entry) for entry in class_2d_folder])
                for entry in select_2d_folder[:]:
                    if os.path.basename(entry) in select_basenames:
                        select_2d_folder.remove(entry)
            else:
                select_basenames = tuple(
                    [os.path.basename(entry) for entry in select_2d_folder])
                for entry in class_2d_folder[:]:
                    if os.path.basename(entry) in select_basenames:
                        class_2d_folder.remove(entry)
        else:
            select_2d_folder.append(os.path.join(self.log_folder,
                                                 input_folder))

        self.fill(class_2d_folder)
        self.fill(select_2d_folder, cinderella=True)
        for label_name in self.labels:
            for idx in reversed(range(self.current_index, len(self.widgets))):
                button = self.widgets[idx]
                self.widgets.remove(button)
                button.setParent(None)
        self.adjust_all_layouts()

    def fill(self, folder, cinderella=False):
        if cinderella:
            labels = (self.good_name, self.bad_name)
        else:
            labels = (self.neutral_name, )

        button_dict = {}
        for sub_folder in folder:
            for label_name in labels:
                suffix = '_{}'.format(label_name) if cinderella else ''
                for file_name in sorted(
                        glob.glob(
                            os.path.join(sub_folder, 'png{}'.format(suffix),
                                         '*'))):
                    match = re.search('/([^/]*)-(\d*)\.+png', file_name)
                    if match is None:
                        continue
                    class_id = int(match.group(2)) - 1
                    class_averages = os.path.join(
                        sub_folder, '' if cinderella else 'ISAC2',
                        match.group(1))
                    try:
                        button = self.widgets[self.current_index]
                        button.isac_class_averages = class_averages
                        button.isac_class_id = class_id
                        button.current_layout = label_name
                    except KeyError:
                        button = MyPushButton(label_name, class_averages,
                                              class_id, self)
                        button.sig_click.connect(self.handle_change)
                        self.widgets.append(button)
                    except IndexError:
                        button = MyPushButton(label_name, class_averages,
                                              class_id, self)
                        button.sig_click.connect(self.handle_change)
                        self.widgets.append(button)
                    button.setIconSize(QSize(50, 50))
                    button.setToolTip(
                        'Class averages: {}\nClass id: {}'.format(
                            class_averages, class_id))
                    button.setIcon(QIcon(file_name))
                    button.setStyleSheet(
                        'QPushButton {color: rgba(0, 0, 0 ,0); background-color: rgba(0, 0, 0, 0); border: 0px; border-color: rgba(0, 0, 0, 0); min-width: 50px; max-width: 50px; min-height: 50px; max-height: 50px}'
                    )
                    button_dict.setdefault(class_averages, []).append(button)
                    self.current_index += 1

        try:
            with open(self.settings_file, 'r') as read:
                self.button_dict = json.load(read)
        except FileNotFoundError:
            pass

        for file_name, buttons in button_dict.items():
            try:
                update = os.path.getmtime(file_name) < os.path.getmtime(
                    self.settings_file)
            except FileNotFoundError:
                update = False

            for button in buttons:
                if update:
                    try:
                        button.current_layout = self.button_dict[
                            self.combo_text.currentText()][file_name][str(
                                button.isac_class_id)]
                    except KeyError:
                        pass
                self.add_to_layout(
                    button.current_layout,
                    just_add=button,
                )

    @pyqtSlot(object, object)
    def handle_change(self, sender, event):
        if sender.current_layout == self.neutral_name:
            if event.button() == Qt.LeftButton:
                self.switch_layout(sender, self.good_name)

            elif event.button() == Qt.RightButton:
                self.switch_layout(sender, self.bad_name)
        else:
            self.switch_layout(sender, self.neutral_name)

    @pyqtSlot()
    def adjust_all_layouts(self):
        try:
            self.columns = int(self.edit.text())
        except Exception as e:
            print(e)
            self.edit.setText(str(self.columns))
            return
        for name in self.layouts:
            self.add_to_layout(name)

    def add_to_layout(self,
                      layout_name,
                      add=None,
                      remove=None,
                      clear=False,
                      just_add=None):
        if just_add:
            self.widgets_dict[layout_name].append(just_add)
            self.layouts[layout_name].addWidget(just_add)
            return

        layout_count = self.layouts[layout_name].count()
        for i in reversed(range(layout_count)):
            item = self.layouts[layout_name].itemAt(i)
            if isinstance(item, QSpacerItem):
                self.layouts[layout_name].removeItem(item)
            elif isinstance(item, QWidgetItem):
                self.layouts[layout_name].removeItem(item)
                #if clear:
                #    item.widget().setParent(None)
            elif isinstance(item, QHBoxLayout):
                for j in reversed(range(item.count())):
                    item_j = item.itemAt(j)
                    if isinstance(item_j, QSpacerItem):
                        item.removeItem(item_j)
                        continue
                    elif isinstance(item_j, QWidgetItem):
                        pass
                        #if clear:
                        #    item_j.widget().setParent(None)
                    elif item_j is None:
                        pass
                    else:
                        assert False, item_j
                self.layouts[layout_name].removeItem(item)
            else:
                assert False, item

        if clear:
            self.widgets_dict[layout_name] = []
            self.current_index = 0
            return
        if remove is not None:
            self.widgets_dict[layout_name].remove(remove)
        if add is not None:
            self.widgets_dict[layout_name].append(add)

        self.labels[layout_name].setText('{}: {}'.format(
            layout_name, len(self.widgets_dict[layout_name])))
        a = np.array([(entry.isac_class_averages, entry.isac_class_id)
                      for entry in self.widgets_dict[layout_name]],
                     dtype='U5000,i8')
        indices = np.argsort(a, order=['f0', 'f1'])
        self.widgets_dict[layout_name] = np.array(
            self.widgets_dict[layout_name], dtype=np.object)[indices].tolist()

        layout = None
        for i in range(len(self.widgets_dict[layout_name])):
            i_hor = i % self.columns
            if i_hor == 0:
                if layout is not None:
                    layout.addStretch(1)
                layout = QHBoxLayout()
                self.layouts[layout_name].addLayout(layout)

            layout.addWidget(self.widgets_dict[layout_name][i])
            self.button_dict.setdefault(
                self.combo_text.currentText(), {}).setdefault(
                    self.widgets_dict[layout_name][i].isac_class_averages,
                    {})[str(self.widgets_dict[layout_name]
                            [i].isac_class_id)] = layout_name

        if layout is not None:
            layout.addStretch(1)
        self.layouts[layout_name].addStretch(1)

        if self.widgets_dict[layout_name]:
            with open(self.settings_file, 'w') as write:
                json.dump(self.button_dict, write, indent=1)
        return self.widgets_dict[layout_name]

    def clear(self):
        for name in self.layouts:
            self.add_to_layout(name, clear=True)

    def switch_layout(self, sender, layout_name):
        self.add_to_layout(sender.current_layout, remove=sender)
        self.add_to_layout(layout_name, add=sender)
        sender.current_layout = layout_name

    @pyqtSlot()
    def retrain(self):
        time_string = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
        classes_folder = self.classes_folder.format(time_string)
        good_folder = self.good_folder.format(time_string)
        bad_folder = self.bad_folder.format(time_string)
        model_out = self.model_out.format(time_string)
        config_out = self.config_out.format(time_string)

        original_folder = os.path.join(classes_folder, self.input_name)
        tu.mkdir_p(original_folder)

        self.current_model = model_out

        config_file = os.path.join(os.path.dirname(__file__), 'templates',
                                   'cinderella_config.json')
        with open(config_file, 'r') as read:
            content = read.read()
        content = content.replace('XXXGOODXXX', good_folder)
        content = content.replace('XXXBADXXX', bad_folder)
        content = content.replace('XXXMODELXXX', model_out)
        with open(config_out, 'w') as write:
            write.write(content)

        for current_name, out_dir_classes in ((self.bad_name, bad_folder),
                                              (self.good_name, good_folder)):
            os.makedirs(out_dir_classes, exist_ok=True)
            index_dict = {}
            widgets = self.add_to_layout(current_name)
            for widget in widgets:
                index_dict.setdefault(widget.isac_class_averages,
                                      []).append(widget.isac_class_id)
            for file_name, index_list in index_dict.items():
                out_filename = file_name.replace(self.log_folder, '').replace(
                    self.project_folder, '').replace('/', '_')
                out_symlink = os.path.join(original_folder, out_filename)
                print(out_filename)
                print(out_symlink)
                if not os.path.islink(out_symlink):
                    tu.symlink_rel(file_name, out_symlink)

                out_file = os.path.join(
                    classes_folder,
                    '{}_{}_list.txt'.format(out_filename, current_name))
                with open(out_file, 'w') as write:
                    write.write('\n'.join(map(str, index_list)))
                cmd = '{} {} {} --list={}'.format(
                    self.e2proc2d_exec, file_name,
                    os.path.join(out_dir_classes, out_filename), out_file)
                print('Execute:', cmd)
                try:
                    subprocess.call(cmd.split())
                except Exception as e:
                    print(e)
        cmd = '{} -c {}'.format(self.sp_cinderella_train_exec, config_out)
        print('Execute:', cmd)
        try:
            idx = subprocess.call(cmd.split())
        except Exception as e:
            print(e)
        else:
            if not idx:
                self.repick(time_string)

    @pyqtSlot()
    def repick(self, time_string=None):
        try:
            if time_string is None:
                classes_folder = os.path.join(
                    self.log_folder,
                    self.combo_text.currentText().rsplit('_', 1)[0])
            else:
                classes_folder = self.classes_folder.format(time_string)
        except ValueError:
            tu.message(
                'Could not find model for current entry: {}.\nPlease provide a repicking run as starting point.'
                .format(self.combo_text.currentText()))
            return

        if not os.path.isdir(classes_folder):
            print(classes_folder)
            tu.message(
                'Could not find model for current combo: {}.\nPlease provide a repicking run as starting point.'
                .format(self.combo_text.currentText()))
            return

        original_folder = os.path.join(classes_folder, self.input_name)
        model_out = os.path.join(classes_folder, self.model_name)
        threshold = float(self.threshold_repick.text())
        output_folder = '{}_{}'.format(classes_folder, threshold)

        if not os.path.isfile(model_out):
            print(classes_folder)
            tu.message(
                'Could not find model for current combo: {}.\nPlease provide a repicking run as starting point.'
                .format(self.combo_text.currentText()))
            return

        try:
            shutil.rmtree(output_folder)
        except Exception:
            pass

        cmd = '{} -i {} -o {} -w {} -t {}'.format(
            self.sp_cinderella_predict_exec,
            original_folder,
            output_folder,
            model_out,
            threshold,
        )
        print('Execute:', cmd)
        try:
            subprocess.call(cmd.split())
        except Exception as e:
            print(e)

        for entry in glob.glob(os.path.join(output_folder, '*.txt')):
            if not entry.endswith('_index_confidence.txt'):
                continue

            file_name = entry.rsplit('_index_confidence.txt', 1)[0]
            for suffix in ('_good', '_bad'):
                out_folder = os.path.join(output_folder,
                                          'png{}'.format(suffix))
                in_file = '{}{}.hdf'.format(file_name, suffix)
                tu.mkdir_p(out_folder)
                cmd = '{} {} {} --outmode=uint16 --unstacking'.format(
                    self.e2proc2d_exec,
                    in_file,
                    os.path.join(out_folder,
                                 '{}.png'.format(os.path.basename(in_file))),
                )
                print('Execute:', cmd)
                try:
                    subprocess.call(cmd.split())
                except Exception as e:
                    print(e)

        self.add_combo_item([os.path.basename(output_folder)])
        cur_text = self.combo_text.blockSignals(True)
        self.combo_text.setCurrentText(os.path.basename(output_folder))
        self.combo_text.blockSignals(cur_text)
        self.combo_text.currentTextChanged.emit(
            os.path.basename(output_folder))

    @pyqtSlot()
    def confirm(self):
        self.sig_new_config.emit(self.model_out, self.threshold)
Beispiel #38
0
class backgroundDlg(ArtisanResizeablDialog):
    def __init__(self, parent = None, aw = None, activeTab = 0):
        super(backgroundDlg,self).__init__(parent, aw)
        self.setWindowTitle(QApplication.translate("Form Caption","Profile Background", None))
        self.setModal(True)
        
        settings = QSettings()
        if settings.contains("BackgroundGeometry"):
            self.restoreGeometry(settings.value("BackgroundGeometry"))
        
        #TAB 1
        self.pathedit = QLineEdit(self.aw.qmc.backgroundpath)
        self.pathedit.setStyleSheet("background-color:'lightgrey';")
        self.pathedit.setReadOnly(True)
        self.pathedit.setFocusPolicy(Qt.NoFocus)
        self.filename = ""
        self.backgroundCheck = QCheckBox(QApplication.translate("CheckBox","Show", None))
        self.backgroundDetails = QCheckBox(QApplication.translate("CheckBox","Annotations", None))
        self.backgroundeventsflag = QCheckBox(QApplication.translate("CheckBox","Events", None))
        self.backgroundDeltaETflag = QCheckBox()
        backgroundDeltaETflagLabel = QLabel(deltaLabelPrefix + QApplication.translate("Label","ET", None))
        self.backgroundDeltaBTflag = QCheckBox()
        backgroundDeltaBTflagLabel = QLabel(deltaLabelPrefix + QApplication.translate("Label","BT", None))
        self.backgroundETflag = QCheckBox(QApplication.translate("CheckBox","ET", None))
        self.backgroundBTflag = QCheckBox(QApplication.translate("CheckBox","BT", None))
        self.backgroundFullflag = QCheckBox(QApplication.translate("CheckBox","Show Full", None))
        self.backgroundCheck.setChecked(self.aw.qmc.background)
        self.backgroundDetails.setChecked(self.aw.qmc.backgroundDetails)
        self.backgroundeventsflag.setChecked(self.aw.qmc.backgroundeventsflag)
        self.backgroundDeltaETflag.setChecked(self.aw.qmc.DeltaETBflag)
        self.backgroundDeltaBTflag.setChecked(self.aw.qmc.DeltaBTBflag)
        self.backgroundETflag.setChecked(self.aw.qmc.backgroundETcurve)
        self.backgroundBTflag.setChecked(self.aw.qmc.backgroundBTcurve)
        self.backgroundFullflag.setChecked(self.aw.qmc.backgroundShowFullflag)
        loadButton = QPushButton(QApplication.translate("Button","Load", None))
        loadButton.setFocusPolicy(Qt.NoFocus)
        delButton = QPushButton(QApplication.translate("Button","Delete", None))
        delButton.setFocusPolicy(Qt.NoFocus)

        # connect the ArtisanDialog standard OK/Cancel buttons
        self.dialogbuttons.accepted.connect(self.accept)
        self.dialogbuttons.removeButton(self.dialogbuttons.button(QDialogButtonBox.Cancel))
        
        alignButton = QPushButton(QApplication.translate("Button","Align", None))
        alignButton.setFocusPolicy(Qt.NoFocus)
        self.alignComboBox = QComboBox()
        alignnames = [
            QApplication.translate("Label","CHARGE", None),
            QApplication.translate("Label","DRY", None),
            QApplication.translate("Label","FCs", None),
            QApplication.translate("Label","FCe", None),
            QApplication.translate("Label","SCs", None),
            QApplication.translate("Label","SCe", None),
            QApplication.translate("Label","DROP", None),
            QApplication.translate("Label","ALL", None),
            ]
        self.alignComboBox.addItems(alignnames)
        self.alignComboBox.setCurrentIndex(self.aw.qmc.alignEvent)
        self.alignComboBox.currentIndexChanged.connect(self.changeAlignEventidx)
        loadButton.clicked.connect(self.load)
        alignButton.clicked.connect(self.timealign)
        
        self.speedSpinBox = QSpinBox()
        self.speedSpinBox.setAlignment(Qt.AlignRight)
        self.speedSpinBox.setRange(1,90)
        self.speedSpinBox.setSingleStep(5)
        self.speedSpinBox.setValue(self.aw.qmc.backgroundmovespeed)
        
        curvenames = [""] # first entry is the empty one, no extra curve displayed
        for i in range(min(len(self.aw.qmc.extraname1B),len(self.aw.qmc.extraname2B),len(self.aw.qmc.extratimexB))):
            curvenames.append("B" + str(2*i+3) + ": " + self.aw.qmc.extraname1B[i])
            curvenames.append("B" + str(2*i+4) + ": " + self.aw.qmc.extraname2B[i])

        self.xtcurvelabel = QLabel(QApplication.translate("Label", "Extra 1",None))
        self.xtcurveComboBox = QComboBox()
        self.xtcurveComboBox.setToolTip(QApplication.translate("Tooltip","For loaded backgrounds with extra devices only",None))
        self.xtcurveComboBox.setMinimumWidth(120)
        self.xtcurveComboBox.addItems(curvenames)
        if self.aw.qmc.xtcurveidx < len(curvenames):
            self.xtcurveComboBox.setCurrentIndex(self.aw.qmc.xtcurveidx)
        self.xtcurveComboBox.currentIndexChanged.connect(self.changeXTcurveidx)

        self.ytcurvelabel = QLabel(QApplication.translate("Label", "Extra 2",None))
        self.ytcurveComboBox = QComboBox()
        self.ytcurveComboBox.setToolTip(QApplication.translate("Tooltip","For loaded backgrounds with extra devices only",None))
        self.ytcurveComboBox.setMinimumWidth(120)
        self.ytcurveComboBox.addItems(curvenames)
        if self.aw.qmc.ytcurveidx < len(curvenames):
            self.ytcurveComboBox.setCurrentIndex(self.aw.qmc.ytcurveidx)
        self.ytcurveComboBox.currentIndexChanged.connect(self.changeYTcurveidx)
        
        self.upButton = QPushButton(QApplication.translate("Button","Up",None))
        self.upButton.setFocusPolicy(Qt.NoFocus)
        self.downButton = QPushButton(QApplication.translate("Button","Down",None))
        self.downButton.setFocusPolicy(Qt.NoFocus)
        self.leftButton = QPushButton(QApplication.translate("Button","Left",None))
        self.leftButton.setFocusPolicy(Qt.NoFocus)
        self.rightButton = QPushButton(QApplication.translate("Button","Right",None))
        self.rightButton.setFocusPolicy(Qt.NoFocus)
        self.backgroundCheck.clicked.connect(self.readChecks)
        self.backgroundDetails.clicked.connect(self.readChecks)
        self.backgroundeventsflag.clicked.connect(self.readChecks)
        self.backgroundDeltaETflag.clicked.connect(self.readChecks)
        self.backgroundDeltaBTflag.clicked.connect(self.readChecks)
        self.backgroundETflag.clicked.connect(self.readChecks)
        self.backgroundBTflag.clicked.connect(self.readChecks)
        self.backgroundFullflag.clicked.connect(self.readChecks)
        delButton.clicked.connect(self.delete)
        self.upButton.clicked.connect(self.moveUp)
        self.downButton.clicked.connect(self.moveDown)
        self.leftButton.clicked.connect(self.moveLeft)
        self.rightButton.clicked.connect(self.moveRight)
        #TAB 2 EVENTS
        #table for showing events
        self.eventtable = QTableWidget()
        self.eventtable.setTabKeyNavigation(True)
        self.createEventTable()
        self.copyeventTableButton = QPushButton(QApplication.translate("Button", "Copy Table",None))
        self.copyeventTableButton.setToolTip(QApplication.translate("Tooltip","Copy table to clipboard, OPTION or ALT click for tabular text",None))
        self.copyeventTableButton.setFocusPolicy(Qt.NoFocus)
        self.copyeventTableButton.setMaximumSize(self.copyeventTableButton.sizeHint())
        self.copyeventTableButton.setMinimumSize(self.copyeventTableButton.minimumSizeHint())
        self.copyeventTableButton.clicked.connect(self.copyEventTabletoClipboard)
        #TAB 3 DATA
        #table for showing data
        self.datatable = QTableWidget()
        self.datatable.setTabKeyNavigation(True)
        self.createDataTable()
        self.copydataTableButton = QPushButton(QApplication.translate("Button", "Copy Table",None))
        self.copydataTableButton.setToolTip(QApplication.translate("Tooltip","Copy table to clipboard, OPTION or ALT click for tabular text",None))
        self.copydataTableButton.setFocusPolicy(Qt.NoFocus)
        self.copydataTableButton.setMaximumSize(self.copydataTableButton.sizeHint())
        self.copydataTableButton.setMinimumSize(self.copydataTableButton.minimumSizeHint())
        self.copydataTableButton.clicked.connect(self.copyDataTabletoClipboard)
        #TAB 4
        self.replayComboBox = QComboBox()
        replayVariants = [
            QApplication.translate("Label","by time", None),
            QApplication.translate("Label","by BT", None),
            QApplication.translate("Label","by ET", None),
            ]
        self.replayComboBox.addItems(replayVariants)
        self.replayComboBox.setCurrentIndex(self.aw.qmc.replayType)
        self.replayComboBox.currentIndexChanged.connect(self.changeReplayTypeidx)
                
        self.backgroundReproduce = QCheckBox(QApplication.translate("CheckBox","Playback Aid",None))
        self.backgroundReproduce.setChecked(self.aw.qmc.backgroundReproduce)
        self.backgroundReproduce.setFocusPolicy(Qt.NoFocus)
        self.backgroundReproduce.stateChanged.connect(self.setreproduce)
        self.backgroundReproduceBeep = QCheckBox(QApplication.translate("CheckBox","Beep",None))
        self.backgroundReproduceBeep.setChecked(self.aw.qmc.backgroundReproduce)
        self.backgroundReproduceBeep.setFocusPolicy(Qt.NoFocus)
        self.backgroundReproduceBeep.stateChanged.connect(self.setreproduceBeep)
        self.backgroundPlaybackEvents = QCheckBox(QApplication.translate("CheckBox","Playback Events",None))
        self.backgroundPlaybackEvents.setChecked(self.aw.qmc.backgroundPlaybackEvents)
        self.backgroundPlaybackEvents.setFocusPolicy(Qt.NoFocus)
        self.backgroundPlaybackEvents.stateChanged.connect(self.setplaybackevent)
        self.backgroundPlaybackDROP = QCheckBox(QApplication.translate("CheckBox","Playback DROP",None))
        self.backgroundPlaybackDROP.setChecked(self.aw.qmc.backgroundPlaybackDROP)
        self.backgroundPlaybackDROP.setFocusPolicy(Qt.NoFocus)
        self.backgroundPlaybackDROP.stateChanged.connect(self.setplaybackdrop)
        etimelabel =QLabel(QApplication.translate("Label", "Text Warning",None))
        etimeunit =QLabel(QApplication.translate("Label", "sec",None))
        self.etimeSpinBox = QSpinBox()
        self.etimeSpinBox.setRange(1,60)
        self.etimeSpinBox.setValue(self.aw.qmc.detectBackgroundEventTime)
        self.etimeSpinBox.valueChanged.connect(self.setreproduce)
        #LAYOUT MANAGERS
        movelayout = QGridLayout()
        movelayout.addWidget(self.upButton,0,1)
        movelayout.addWidget(self.leftButton,1,0)
        movelayout.addWidget(self.speedSpinBox,1,1)
        movelayout.addWidget(self.rightButton,1,2)
        movelayout.addWidget(self.downButton,2,1)
        movelayout.setSpacing(20)
        checkslayout1 = QHBoxLayout()
        checkslayout1.addStretch()
        checkslayout1.addWidget(self.backgroundCheck)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundDetails)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundeventsflag)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundETflag)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundBTflag)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundDeltaETflag)
        checkslayout1.addSpacing(3)
        checkslayout1.addWidget(backgroundDeltaETflagLabel)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundDeltaBTflag)
        checkslayout1.addSpacing(3)
        checkslayout1.addWidget(backgroundDeltaBTflagLabel)
        checkslayout1.addSpacing(5)
        checkslayout1.addWidget(self.backgroundFullflag)
        checkslayout1.addStretch()
        layout = QGridLayout()
        layoutBoxedH = QHBoxLayout()
        layoutBoxedH.addStretch()
        layoutBoxedH.addLayout(movelayout)
        layoutBoxedH.addLayout(layout)
        layoutBoxedH.addStretch()
        layoutBoxed = QVBoxLayout()
        layoutBoxed.addStretch()
        layoutBoxed.addLayout(checkslayout1)
        layoutBoxed.addStretch()
        layoutBoxed.addLayout(layoutBoxedH)
        layoutBoxed.addStretch()
        alignButtonBoxed = QHBoxLayout()
        alignButtonBoxed.addWidget(self.xtcurvelabel)
        alignButtonBoxed.addWidget(self.xtcurveComboBox)
        alignButtonBoxed.addSpacing(10)
        alignButtonBoxed.addWidget(self.ytcurvelabel)
        alignButtonBoxed.addWidget(self.ytcurveComboBox)
        alignButtonBoxed.addStretch()
        alignButtonBoxed.addWidget(alignButton)
        alignButtonBoxed.addWidget(self.alignComboBox)
        tab4content = QHBoxLayout()
        tab4content.addWidget(self.backgroundReproduce)
        tab4content.addSpacing(10)
        tab4content.addWidget(self.backgroundReproduceBeep)
        tab4content.addSpacing(10)
        tab4content.addWidget(etimelabel)
        tab4content.addWidget(self.etimeSpinBox)
        tab4content.addWidget(etimeunit)
        tab4content.addSpacing(20)
        tab4content.addStretch()
        tab4content.addWidget(self.backgroundPlaybackEvents)
        tab4content.addSpacing(10)
        tab4content.addWidget(self.backgroundPlaybackDROP)
        tab4content.addSpacing(10)
        tab4content.addWidget(self.replayComboBox)
        tab1layout = QVBoxLayout()
        tab1layout.addLayout(layoutBoxed)
#        tab1layout.addStretch()
        tab1layout.addLayout(alignButtonBoxed)
        tab1layout.addLayout(tab4content)
        tab1layout.setContentsMargins(5, 0, 5, 0) # left, top, right, bottom
        eventbuttonLayout = QHBoxLayout()
        eventbuttonLayout.addWidget(self.copyeventTableButton)
        eventbuttonLayout.addStretch()
        tab2layout = QVBoxLayout()
        tab2layout.addWidget(self.eventtable)
        tab2layout.addLayout(eventbuttonLayout)
        tab2layout.setContentsMargins(5, 0, 5, 0) # left, top, right, bottom
        databuttonLayout = QHBoxLayout()
        databuttonLayout.addWidget(self.copydataTableButton)
        databuttonLayout.addStretch()
        tab3layout = QVBoxLayout()
        tab3layout.addWidget(self.datatable)
        tab3layout.addLayout(databuttonLayout)
        tab3layout.setContentsMargins(5, 0, 5, 0) # left, top, right, bottom
        #tab layout
        tab1layout.setSpacing(5)
        self.TabWidget = QTabWidget()
        C1Widget = QWidget()
        C1Widget.setLayout(tab1layout)
        self.TabWidget.addTab(C1Widget,QApplication.translate("Tab","Config",None))
        C2Widget = QWidget()
        C2Widget.setLayout(tab2layout)
        self.TabWidget.addTab(C2Widget,QApplication.translate("Tab","Events",None))
        C3Widget = QWidget()
        C3Widget.setLayout(tab3layout)
        self.TabWidget.addTab(C3Widget,QApplication.translate("Tab","Data",None))
        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(loadButton)
        buttonLayout.addWidget(delButton)
        buttonLayout.addStretch()
        buttonLayout.addWidget(self.dialogbuttons)
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.TabWidget) 
        mainLayout.addWidget(self.pathedit)
        mainLayout.addLayout(buttonLayout)
        mainLayout.setContentsMargins(5, 10, 5, 5) # left, top, right, bottom 
        self.setLayout(mainLayout)
        if platform.system() == 'Windows':
            self.dialogbuttons.button(QDialogButtonBox.Ok)
        else:
            self.dialogbuttons.button(QDialogButtonBox.Ok).setFocus()
        self.TabWidget.setCurrentIndex(activeTab)
    
    @pyqtSlot(bool)
    def timealign(self,_):
        self.aw.qmc.timealign()
    
    #keyboard presses. There must not be widgets (pushbuttons, comboboxes, etc) in focus in order to work 
    def keyPressEvent(self,event):
        if event.matches(QKeySequence.Copy):
            if self.TabWidget.currentIndex() == 2: # datatable
                self.aw.copy_cells_to_clipboard(self.datatable)
                self.aw.sendmessage(QApplication.translate("Message","Data table copied to clipboard",None))
        else:
            super(backgroundDlg,self).keyPressEvent(event)

    @pyqtSlot()
    def accept(self):
        self.aw.qmc.backgroundmovespeed = self.speedSpinBox.value()
        self.close()
        
    def closeEvent(self,_):
        settings = QSettings()
        #save window geometry
        settings.setValue("BackgroundGeometry",self.saveGeometry())
        self.aw.backgroundDlg_activeTab = self.TabWidget.currentIndex()
        
    def getColorIdx(self,c):
        try:
            return self.defaultcolorsmapped.index(c)
        except Exception:
            try:
                return self.colors.index(c) + 5
            except Exception: 
                return 0

    @pyqtSlot(int)
    def setplaybackevent(self,_):
        s = None
        if self.backgroundPlaybackEvents.isChecked():
            self.aw.qmc.backgroundPlaybackEvents = True
            msg = QApplication.translate("Message","Playback Events set ON",None)
        else:
            self.aw.qmc.backgroundPlaybackEvents = False
            msg = QApplication.translate("StatusBar","Playback Events set OFF",None)
            s = "background-color:'transparent';"
        self.aw.sendmessage(msg, style=s)

    @pyqtSlot(int)
    def setplaybackdrop(self,_):
        s = None
        if self.backgroundPlaybackDROP.isChecked():
            self.aw.qmc.backgroundPlaybackDROP = True
            msg = QApplication.translate("Message","Playback DROP set ON",None)
        else:
            self.aw.qmc.backgroundPlaybackDROP = False
            msg = QApplication.translate("StatusBar","Playback DROP set OFF",None)
            s = "background-color:'transparent';"
        self.aw.sendmessage(msg, style=s)
                
    @pyqtSlot(int)
    def setreproduceBeep(self,_):
        if self.backgroundReproduceBeep.isChecked():
            self.aw.qmc.backgroundReproduceBeep = True
        else:
            self.aw.qmc.backgroundReproduceBeep = False

    @pyqtSlot(int)
    def setreproduce(self,_):
        self.aw.qmc.detectBackgroundEventTime = self.etimeSpinBox.value()
        s = None
        if self.backgroundReproduce.isChecked():
            self.aw.qmc.backgroundReproduce = True
            msg = QApplication.translate("Message","Playback Aid set ON at {0} secs",None).format(str(self.aw.qmc.detectBackgroundEventTime))
        else:
            self.aw.qmc.backgroundReproduce = False
            msg = QApplication.translate("StatusBar","Playback Aid set OFF",None)
            s = "background-color:'transparent';"
        self.aw.sendmessage(msg, style=s)

    def adjustcolor(self,curve):
        
        curve = str(curve).lower()

        etcolor = str(self.metcolorComboBox.currentText()).lower()
        btcolor = str(self.btcolorComboBox.currentText()).lower()
        deltabtcolor = str(self.deltabtcolorComboBox.currentText()).lower()
        deltaetcolor = str(self.deltaetcolorComboBox.currentText()).lower()
        xtcolor = str(self.xtcolorComboBox.currentText()).lower()

        defaults =  ["et","bt","deltaet","deltabt"]
        
        if curve == "et":
            if etcolor in defaults:
                self.aw.qmc.backgroundmetcolor = self.aw.qmc.palette[etcolor]
            else:
                self.aw.qmc.backgroundmetcolor = etcolor
                
        elif curve == "bt":
            if btcolor in defaults:
                self.aw.qmc.backgroundbtcolor = self.aw.qmc.palette[btcolor]
            else:
                self.aw.qmc.backgroundbtcolor = btcolor

        elif curve == "deltaet":
            if deltaetcolor in defaults:
                self.aw.qmc.backgrounddeltaetcolor = self.aw.qmc.palette[deltaetcolor]
            else:
                self.aw.qmc.backgrounddeltaetcolor = deltaetcolor
            
        elif curve == "deltabt":
            if deltabtcolor in defaults:
                self.aw.qmc.backgrounddeltabtcolor = self.aw.qmc.palette[deltabtcolor]
            else:
                self.aw.qmc.backgrounddeltabtcolor = deltabtcolor

        elif curve == "xt":
            if xtcolor in defaults:
                self.aw.qmc.backgroundxtcolor = self.aw.qmc.palette[xtcolor]
            else:
                self.aw.qmc.backgroundxtcolor = xtcolor 

        self.aw.qmc.redraw(recomputeAllDeltas=False)

    @pyqtSlot(bool)
    def delete(self,_):
        self.pathedit.setText("")
# we should not overwrite the users app settings here, right:
# but we have to deactivate the show flag
        self.backgroundCheck.setChecked(False)
        self.aw.qmc.background = False
        self.aw.qmc.backgroundprofile = None
        self.xtcurveComboBox.blockSignals(True)
        self.xtcurveComboBox.clear()
        self.aw.deleteBackground()
        self.eventtable.clear()
        self.createEventTable()
        self.createDataTable()
        self.aw.qmc.resetlinecountcaches()
        self.xtcurveComboBox.blockSignals(False)
        self.aw.qmc.redraw(recomputeAllDeltas=False)

    @pyqtSlot(bool)
    def moveUp(self,_):
        self.upButton.setDisabled(True)
        self.move("up")
        self.upButton.setDisabled(False)
    @pyqtSlot(bool)
    def moveDown(self,_):
        self.downButton.setDisabled(True)
        self.move("down")
        self.downButton.setDisabled(False)
    @pyqtSlot(bool)
    def moveLeft(self,_):
        self.leftButton.setDisabled(True)
        self.move("left")
        self.leftButton.setDisabled(False)
    @pyqtSlot(bool)
    def moveRight(self,_):
        self.rightButton.setDisabled(True)
        self.move("right")
        self.rightButton.setDisabled(False)
    
    def move(self,m):
        step = self.speedSpinBox.value()
        self.aw.qmc.movebackground(m,step)
        self.createEventTable()
        self.createDataTable()
        self.aw.qmc.redraw(recomputeAllDeltas=False)

    def readChecks(self):
        self.aw.qmc.background = bool(self.backgroundCheck.isChecked())
        self.aw.qmc.backgroundDetails = bool(self.backgroundDetails.isChecked())
        self.aw.qmc.backgroundeventsflag = bool(self.backgroundeventsflag.isChecked())
        self.aw.qmc.DeltaETBflag = bool(self.backgroundDeltaETflag.isChecked())
        self.aw.qmc.DeltaBTBflag = bool(self.backgroundDeltaBTflag.isChecked())
        self.aw.qmc.backgroundETcurve = bool(self.backgroundETflag.isChecked())
        self.aw.qmc.backgroundBTcurve = bool(self.backgroundBTflag.isChecked())
        self.aw.qmc.backgroundShowFullflag = bool(self.backgroundFullflag.isChecked())
        self.aw.qmc.redraw(recomputeAllDeltas=True)
    
    @pyqtSlot(int)
    def changeAlignEventidx(self,i):
        self.aw.qmc.alignEvent = i
        
    @pyqtSlot(int)
    def changeReplayTypeidx(self,i):
        self.aw.qmc.replayType = i

    @pyqtSlot(int)
    def changeXTcurveidx(self,i):
        self.aw.qmc.xtcurveidx = i
        self.createDataTable()
        self.aw.qmc.redraw(recomputeAllDeltas=False,smooth=True)

    @pyqtSlot(int)
    def changeYTcurveidx(self,i):
        self.aw.qmc.ytcurveidx = i
        self.createDataTable()
        self.aw.qmc.redraw(recomputeAllDeltas=False,smooth=True)

    @pyqtSlot(bool)
    def load(self,_):
        self.filename = self.aw.ArtisanOpenFileDialog(msg=QApplication.translate("Message","Load Background",None),ext_alt=".alog")
        if len(self.filename) == 0:
            return
        self.aw.sendmessage(QApplication.translate("Message","Reading background profile...",None))
        self.aw.qmc.resetlinecountcaches()
        self.aw.loadbackground(self.filename)
        
        # reset XT curve popup
        curvenames = [""] # first entry is the empty one (no extra curve displayed)
        for i in range(min(len(self.aw.qmc.extraname1B),len(self.aw.qmc.extraname2B),len(self.aw.qmc.extratimexB))):
            curvenames.append("B" + str(2*i+3) + ": " + self.aw.qmc.extraname1B[i])
            curvenames.append("B" + str(2*i+4) + ": " + self.aw.qmc.extraname2B[i])
            
        self.xtcurveComboBox.blockSignals(True)
        self.xtcurveComboBox.clear()
        self.xtcurveComboBox.addItems(curvenames)
        if self.aw.qmc.xtcurveidx < len(curvenames):
            self.xtcurveComboBox.setCurrentIndex(self.aw.qmc.xtcurveidx)
        self.xtcurveComboBox.blockSignals(False)

        self.ytcurveComboBox.blockSignals(True)
        self.ytcurveComboBox.clear()
        self.ytcurveComboBox.addItems(curvenames)
        if self.aw.qmc.ytcurveidx < len(curvenames):
            self.ytcurveComboBox.setCurrentIndex(self.aw.qmc.ytcurveidx)
        self.ytcurveComboBox.blockSignals(False)

        self.pathedit.setText(self.filename)
        self.backgroundCheck.setChecked(True)
        self.aw.qmc.timealign(redraw=False)
        self.readChecks()
        self.createEventTable()
        self.createDataTable()

    def createEventTable(self):
        ndata = len(self.aw.qmc.backgroundEvents)
        
        # self.eventtable.clear() # this crashes Ubuntu 16.04
#        if ndata != 0:
#            self.eventtable.clearContents() # this crashes Ubuntu 16.04 if device table is empty and also sometimes else
        self.eventtable.clearSelection() # this seems to work also for Ubuntu 16.04
        
        self.eventtable.setRowCount(ndata)
        self.eventtable.setColumnCount(6)
        self.eventtable.setHorizontalHeaderLabels([QApplication.translate("Table","Time",None),
                                                   QApplication.translate("Table", "ET", None),
                                                   QApplication.translate("Table", "BT", None),
                                                   QApplication.translate("Table","Description",None),
                                                   QApplication.translate("Table","Type",None),
                                                   QApplication.translate("Table","Value",None)])
        self.eventtable.setAlternatingRowColors(True)
        self.eventtable.setEditTriggers(QTableWidget.NoEditTriggers)
        self.eventtable.setSelectionBehavior(QTableWidget.SelectRows)
        self.eventtable.setSelectionMode(QTableWidget.ExtendedSelection)
        self.eventtable.setShowGrid(True)
        self.eventtable.verticalHeader().setSectionResizeMode(2)
        if self.aw.qmc.timeindex[0] != -1:
            start = self.aw.qmc.timex[self.aw.qmc.timeindex[0]]
        else:
            start = 0
        for i in range(ndata):
            timez = QTableWidgetItem(stringfromseconds(self.aw.qmc.timeB[self.aw.qmc.backgroundEvents[i]]-start))
            timez.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
    
            if self.aw.qmc.LCDdecimalplaces:
                fmtstr = "%.1f"
            else:
                fmtstr = "%.0f"
            
            etline = QTableWidgetItem(fmtstr%(self.aw.qmc.temp1B[self.aw.qmc.backgroundEvents[i]]) + self.aw.qmc.mode)
            etline.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
            
            btline = QTableWidgetItem(fmtstr%(self.aw.qmc.temp2B[self.aw.qmc.backgroundEvents[i]]) + self.aw.qmc.mode)
            btline.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
            
            description = QTableWidgetItem(self.aw.qmc.backgroundEStrings[i])
            etype = QTableWidgetItem(self.aw.qmc.Betypesf(self.aw.qmc.backgroundEtypes[i]))
            evalue = QTableWidgetItem(self.aw.qmc.eventsvalues(self.aw.qmc.backgroundEvalues[i]))
            evalue.setTextAlignment(Qt.AlignRight + Qt.AlignVCenter)
            #add widgets to the table
            self.eventtable.setItem(i,0,timez)
            self.eventtable.setItem(i,1,etline)
            self.eventtable.setItem(i,2,btline)
            self.eventtable.setItem(i,3,description)
            self.eventtable.setItem(i,4,etype)
            self.eventtable.setItem(i,5,evalue)
        # improve width of Time column
        self.eventtable.setColumnWidth(1,175)
        header = self.eventtable.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.Fixed)
        header.setSectionResizeMode(1, QHeaderView.Fixed)
        header.setSectionResizeMode(2, QHeaderView.Fixed)
        header.setSectionResizeMode(3, QHeaderView.Stretch)
        header.setSectionResizeMode(4, QHeaderView.Fixed)
        header.setSectionResizeMode(5, QHeaderView.Fixed)
        self.eventtable.resizeColumnsToContents()
        self.eventtable.setColumnWidth(1,65)
        self.eventtable.setColumnWidth(2,65)

    def createDataTable(self):
        try:
            #### lock shared resources #####
            self.aw.qmc.samplingsemaphore.acquire(1)
            
            ndata = len(self.aw.qmc.timeB)
            
            self.datatable.clear() # this crashes Ubuntu 16.04
    #        if ndata != 0:
    #            self.datatable.clearContents() # this crashes Ubuntu 16.04 if device table is empty and also sometimes else
            self.datatable.clearSelection() # this seems to work also for Ubuntu 16.04
    
            if self.aw.qmc.timeindexB[0] != -1 and len(self.aw.qmc.timeB) > self.aw.qmc.timeindexB[0]:
                start = self.aw.qmc.timeB[self.aw.qmc.timeindexB[0]]
            else:
                start = 0
            self.datatable.setRowCount(ndata)
            headers = [QApplication.translate("Table","Time",None),
                                                      QApplication.translate("Table","ET",None),
                                                      QApplication.translate("Table","BT",None),
                                                      deltaLabelUTF8 + QApplication.translate("Table","ET",None),
                                                      deltaLabelUTF8 + QApplication.translate("Table","BT",None)]
            xtcurve = False # no XT curve
            if self.aw.qmc.xtcurveidx > 0: # 3rd background curve set?
                idx3 = self.aw.qmc.xtcurveidx - 1
                n3 = idx3 // 2
                if len(self.aw.qmc.temp1BX) > n3 and len(self.aw.qmc.extratimexB) > n3:
                    xtcurve = True
                    if self.aw.qmc.xtcurveidx % 2:
                        headers.append(self.aw.qmc.extraname1B[n3])
                    else:
                        headers.append(self.aw.qmc.extraname2B[n3])

            ytcurve = False # no YT curve
            if self.aw.qmc.ytcurveidx > 0: # 4th background curve set?
                idx4 = self.aw.qmc.ytcurveidx - 1
                n4 = idx4 // 2
                if len(self.aw.qmc.temp1BX) > n4 and len(self.aw.qmc.extratimexB) > n4:
                    ytcurve = True
                    if self.aw.qmc.ytcurveidx % 2:
                        headers.append(self.aw.qmc.extraname1B[n4])
                    else:
                        headers.append(self.aw.qmc.extraname2B[n4])
            
            headers.append("") # dummy column that stretches
            self.datatable.setColumnCount(len(headers))
            self.datatable.setHorizontalHeaderLabels(headers)
            self.datatable.setAlternatingRowColors(True)
            self.datatable.setEditTriggers(QTableWidget.NoEditTriggers)
            self.datatable.setSelectionBehavior(QTableWidget.SelectRows)
            self.datatable.setSelectionMode(QTableWidget.ExtendedSelection) # QTableWidget.SingleSelection, ContiguousSelection, MultiSelection
            self.datatable.setShowGrid(True)
            self.datatable.verticalHeader().setSectionResizeMode(2)
            for i in range(ndata):
                Rtime = QTableWidgetItem(stringfromseconds(self.aw.qmc.timeB[i]-start))
                Rtime.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                if self.aw.qmc.LCDdecimalplaces:
                    fmtstr = "%.1f"
                else:
                    fmtstr = "%.0f"
                ET = QTableWidgetItem(fmtstr%self.aw.qmc.temp1B[i])
                BT = QTableWidgetItem(fmtstr%self.aw.qmc.temp2B[i])
                ET.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                BT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                if i:
                    d = (self.aw.qmc.timeB[i]-self.aw.qmc.timeB[i-1])
                    if d == 0:
                        dET = 0.
                        dBT = 0.
                    else:
                        dET = (60*(self.aw.qmc.temp1B[i]-self.aw.qmc.temp1B[i-1])/d)
                        dBT = (60*(self.aw.qmc.temp2B[i]-self.aw.qmc.temp2B[i-1])/d)
                    deltaET = QTableWidgetItem("%.1f"%dET)
                    deltaBT = QTableWidgetItem("%.1f"%dBT)
                else:
                    deltaET = QTableWidgetItem("--")
                    deltaBT = QTableWidgetItem("--")
                deltaET.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                deltaBT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                self.datatable.setItem(i,0,Rtime)
                        
                if i:
                    #identify by color and add notation
                    if i == self.aw.qmc.timeindexB[0] != -1:
                        self.datatable.item(i,0).setBackground(QColor('#f07800'))
                        text = QApplication.translate("Table", "CHARGE",None)
                    elif i == self.aw.qmc.timeindexB[1]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "DRY END",None)
                    elif i == self.aw.qmc.timeindexB[2]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "FC START",None)
                    elif i == self.aw.qmc.timeindexB[3]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "FC END",None)
                    elif i == self.aw.qmc.timeindexB[4]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "SC START",None)
                    elif i == self.aw.qmc.timeindexB[5]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "SC END",None)
                    elif i == self.aw.qmc.timeindexB[6]:
                        self.datatable.item(i,0).setBackground(QColor('#f07800'))
                        text = QApplication.translate("Table", "DROP",None)
                    elif i == self.aw.qmc.timeindexB[7]:
                        self.datatable.item(i,0).setBackground(QColor('orange'))
                        text = QApplication.translate("Table", "COOL",None)
                    elif i in self.aw.qmc.backgroundEvents:
                        self.datatable.item(i,0).setBackground(QColor('yellow'))
                        index = self.aw.qmc.backgroundEvents.index(i)
                        text = QApplication.translate("Table", "#{0} {1}{2}",None).format(str(index+1),self.aw.qmc.Betypesf(self.aw.qmc.backgroundEtypes[index])[0],self.aw.qmc.eventsvalues(self.aw.qmc.backgroundEvalues[index]))
                    else:
                        text = ""
                    Rtime.setText(text + " " + Rtime.text())
                self.datatable.setItem(i,1,ET)
                self.datatable.setItem(i,2,BT)
                self.datatable.setItem(i,3,deltaET)
                self.datatable.setItem(i,4,deltaBT)
                
                if xtcurve and len(self.aw.qmc.temp1BX[n3]) > i: # an XT column is availble, fill it with data
                    if self.aw.qmc.xtcurveidx % 2:
                        XT = QTableWidgetItem("%.0f"%self.aw.qmc.temp1BX[n3][i])
                    else:
                        XT = QTableWidgetItem("%.0f"%self.aw.qmc.temp2BX[n3][i])
                    XT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                    self.datatable.setItem(i,5,XT)
                
                if ytcurve and len(self.aw.qmc.temp1BX[n4]) > i: # an YT column is availble, fill it with data
                    if self.aw.qmc.ytcurveidx % 2:
                        YT = QTableWidgetItem("%.0f"%self.aw.qmc.temp1BX[n4][i])
                    else:
                        YT = QTableWidgetItem("%.0f"%self.aw.qmc.temp2BX[n4][i])
                    YT.setTextAlignment(Qt.AlignRight|Qt.AlignVCenter)
                    if xtcurve:
                        self.datatable.setItem(i,6,YT)
                    else:
                        self.datatable.setItem(i,5,YT)
                    
            header = self.datatable.horizontalHeader()
            header.setSectionResizeMode(0, QHeaderView.Fixed)
            header.setSectionResizeMode(1, QHeaderView.Fixed)
            header.setSectionResizeMode(2, QHeaderView.Fixed)
            header.setSectionResizeMode(3, QHeaderView.Fixed)
            header.setSectionResizeMode(4, QHeaderView.Fixed)
            if (xtcurve and not ytcurve) or (ytcurve and not xtcurve):
                header.setSectionResizeMode(5, QHeaderView.Fixed)
                header.setSectionResizeMode(6, QHeaderView.Stretch)
            elif xtcurve and ytcurve:
                header.setSectionResizeMode(5, QHeaderView.Fixed)
                header.setSectionResizeMode(6, QHeaderView.Fixed)
                header.setSectionResizeMode(7, QHeaderView.Stretch)
            else:
                header.setSectionResizeMode(5, QHeaderView.Stretch)
            self.datatable.resizeColumnsToContents()
        finally:
            if self.aw.qmc.samplingsemaphore.available() < 1:
                self.aw.qmc.samplingsemaphore.release(1)

    @pyqtSlot(bool)
    def copyDataTabletoClipboard(self,_=False):
        self.datatable.selectAll()
        self.aw.copy_cells_to_clipboard(self.datatable,adjustment=7)
        self.datatable.clearSelection()
        self.aw.sendmessage(QApplication.translate("Message","Data table copied to clipboard",None))

    @pyqtSlot(bool)
    def copyEventTabletoClipboard(self,_=False):
        self.aw.copy_cells_to_clipboard(self.eventtable,adjustment=0)
        self.aw.sendmessage(QApplication.translate("Message","Event table copied to clipboard",None))
Beispiel #39
0
class ParamsByType(QWidget, MooseWidget):
    """
    Has a QComboBox for the different allowed types.
    On switching type a new ParamsByGroup is shown.
    """
    needBlockList = pyqtSignal(list)
    blockRenamed = pyqtSignal(object, str)
    changed = pyqtSignal()

    def __init__(self, block, type_block_map, **kwds):
        """
        Constructor.
        Input:
            block[BlockInfo]: The block to show.
        """
        super(ParamsByType, self).__init__(**kwds)
        self.block = block
        self.combo = QComboBox()
        self.types = []
        self.type_params_map = {}
        self.type_block_map = type_block_map
        self.table_stack = QStackedWidget()
        self.type_table_map = {}

        for t in sorted(self.block.types.keys()):
            self.types.append(t)
            params_list = []
            for p in self.block.parameters_list:
                params_list.append(self.block.parameters[p])
            t_block = self.block.types[t]
            for p in t_block.parameters_list:
                params_list.append(t_block.parameters[p])
            self.type_params_map[t] = params_list

        self.combo.addItems(sorted(self.block.types.keys()))
        self.combo.currentTextChanged.connect(self.setBlockType)

        self.top_layout = WidgetUtils.addLayout(vertical=True)
        self.top_layout.addWidget(self.combo)
        self.top_layout.addWidget(self.table_stack)
        self.setLayout(self.top_layout)
        self.user_params = []
        self.setDefaultBlockType()

        self.setup()

    def _syncUserParams(self, current, to):
        """
        Sync user added parameters that are on the main block into
        each type ParamsByGroup.
        Input:
            current[ParamsByGroup]: The current group parameter table
            to[ParamsByGroup]: The new group parameter table
        """
        ct = current.findTable("Main")
        tot = to.findTable("Main")
        if not ct or not tot or ct == tot:
            return
        tot.removeUserParams()
        params = ct.getUserParams()
        tot.addUserParams(params)
        to.syncParamsFrom(current)
        # Make sure the name parameter stays the same
        idx = ct.findRow("Name")
        if idx >= 0:
            name = ct.item(idx, 1).text()
            idx = tot.findRow("Name")
            if idx >= 0:
                tot.item(idx, 1).setText(name)

    def currentType(self):
        return self.combo.currentText()

    def save(self):
        """
        Look at the user params in self.block.parameters.
        update the type tables
        Save type on block
        """
        t = self.getTable()
        if t:
            t.save()
            self.block.setBlockType(self.combo.currentText())

    def reset(self):
        t = self.getTable()
        t.reset()

    def getOrCreateTypeTable(self, type_name):
        """
        Gets the table for the type name or create it if it doesn't exist.
        Input:
            type_name[str]: Name of the type
        Return:
            ParamsByGroup: The parameters corresponding to the type
        """
        t = self.type_table_map.get(type_name)
        if t:
            return t
        t = ParamsByGroup(self.block, self.type_params_map.get(type_name, self.block.orderedParameters()), self.type_block_map)
        t.needBlockList.connect(self.needBlockList)
        t.blockRenamed.connect(self.blockRenamed)
        t.changed.connect(self.changed)
        self.type_table_map[type_name] = t
        self.table_stack.addWidget(t)
        return t

    def setDefaultBlockType(self):
        param = self.block.getParamInfo("type")
        if param and param.value:
            self.setBlockType(param.value)
        elif self.block.types:
            self.setBlockType(sorted(self.block.types.keys())[0])

    def setBlockType(self, type_name):
        if type_name not in self.block.types:
            return
        t = self.getOrCreateTypeTable(type_name)
        t.updateWatchers()
        self.combo.blockSignals(True)
        self.combo.setCurrentText(type_name)
        self.combo.blockSignals(False)
        t.updateType(type_name)
        current = self.table_stack.currentWidget()
        self._syncUserParams(current, t)
        self.table_stack.setCurrentWidget(t)
        self.changed.emit()

    def addUserParam(self, param):
        t = self.table_stack.currentWidget()
        t.addUserParam(param)

    def setWatchedBlockList(self, path, children):
        for i in range(self.table_stack.count()):
            t = self.table_stack.widget(i)
            t.setWatchedBlockList(path, children)

    def updateWatchers(self):
        for i in range(self.table_stack.count()):
            t = self.table_stack.widget(i)
            t.updateWatchers()

    def getTable(self):
        return self.table_stack.currentWidget()

    def paramValue(self, name):
        for i in range(self.table_stack.count()):
            t = self.table_stack.widget(i)
            if t.paramValue(name):
                return t.paramValue(name)
class FrameCheckOption(QWidget):
    def __init__(self, parent: QObject, controller: TouchManagerController,
                 model: TouchManagerModel):
        super(QWidget, self).__init__()
        self.parent = parent
        self.model = model
        self.controller = controller
        self.main_lay = QVBoxLayout()
        self.bottom_lay = QVBoxLayout()
        self.scroll_wid = QWidget()
        self.scrollable = QScrollArea()
        self.lay = QVBoxLayout()
        self.lbls = []
        self.lblsColors = []
        self.lblImageColors = []
        self.rBtns = []
        self.btnAddCoord = QPushButton()
        self.aroundLbl = QLabel()
        self.cBoxAround = QComboBox()
        self.initMainUI()
        self.initUI({
            'coordinates': [[0.5, 0.5]],
            'values': [[255, 255, 255]],
            'around': 5,
            'currentScreenColors': [[255, 255, 255]]
        })
        self.initConnectors()

    def initMainUI(self):
        self.setLayout(self.main_lay)
        self.aroundLbl.setText("Around factor:")
        self.cBoxAround.addItems(str(i) for i in range(self.model.MAX_AROUND))
        self.cBoxAround.setFixedHeight(20)
        self.cBoxAround.setMaximumWidth(100)
        self.cBoxAround.currentIndexChanged.connect(
            self.controller.requestChangeAround)
        self.btnAddCoord.setText("add coordinate")
        self.btnAddCoord.clicked.connect(
            self.controller.requestFrameCheckCoordAdd)

        self.lay.setAlignment(Qt.AlignTop)
        self.scroll_wid.setLayout(self.lay)
        self.scrollable.setWidgetResizable(True)
        self.scrollable.setWidget(self.scroll_wid)
        self.scrollable.setContentsMargins(0, 0, 0, 0)

        self.main_lay.addWidget(self.scrollable)

        self.bottom_lay.addWidget(self.btnAddCoord)
        h_lay = QHBoxLayout()
        h_lay.addWidget(self.aroundLbl)
        h_lay.addWidget(self.cBoxAround)
        self.bottom_lay.addLayout(h_lay)

        self.main_lay.addLayout(self.bottom_lay)

    def _clearLayout(self):
        self.lbls.clear()
        self.lbls = []
        self.rBtns.clear()
        self.rBtns = []
        self.lblsColors.clear()
        self.lblsColors = []
        self.lblImageColors.clear()
        self.lblImageColors = []
        for i in reversed(range(self.lay.count())):
            row_lay = self.lay.takeAt(i)
            for j in reversed(range(row_lay.count())):
                row_lay.itemAt(j).widget().setParent(None)
            row_lay.setParent(None)

    def _setAroundSafe(self, around):
        self.cBoxAround.blockSignals(True)
        self.cBoxAround.setCurrentIndex(around)
        self.cBoxAround.blockSignals(False)

    def initUI(self, newData: dict):
        if 'around' in newData:
            self._setAroundSafe(newData['around'])
        coords_num = len(newData['coordinates'])
        l = len(newData['currentScreenColors'])
        w, h = self.controller.current_image_size
        for i in range(coords_num):
            lay_row = QHBoxLayout()
            coord = newData['coordinates'][i]
            x, y = int((coord[0] * w)), int((coord[1] * h))
            lbl_point = QLabel("%15s" % ("C%d: %4d , %4d" % (i, x, y)))
            lbl_point.setFixedWidth(80)
            lay_row.addWidget(lbl_point)
            # lay_row.addWidget(QLabel("X: %4d" % (coord[0] * w)))
            # lay_row.addWidget(QLabel("Y: %4d" % (coord[1] * h)))
            colors = newData['values'][i]
            lblColor = QLabel("")
            lblColor.setStyleSheet("background-color: rgb({},{},{});".format(
                colors[0], colors[1], colors[2]))
            lblColor.mousePressEvent = (partial(self.onManualChoose, i))
            lblColor.setToolTip("Target value RGB=(%d, %d, %d)" %
                                (colors[0], colors[1], colors[2]))
            lblColor.setMaximumWidth(40)
            self.lblsColors.append(lblColor)
            btnSet = QPushButton("set->")
            btnSet.setMaximumWidth(45)
            btnSet.clicked.connect(
                partial(
                    self.controller.requestSetCurrentColorToFrameCheckColor,
                    i))
            lblimgColor = QLabel("")
            lblimgColor.setMaximumWidth(20)
            color_ = newData['currentScreenColors'][i]
            lblimgColor.setStyleSheet(
                "background-color: rgb({},{},{});".format(
                    color_[0], color_[1], color_[2]))
            lblimgColor.setToolTip("Current screenshot RGB=(%d, %d, %d)" %
                                   (color_[0], color_[1], color_[2]))
            lblimgColor.setToolTipDuration(20 * 1000)
            self.lblImageColors.append(lblimgColor)
            lay_row.addWidget(lblimgColor)
            lay_row.addWidget(btnSet)
            lay_row.addWidget(lblColor)
            rbtn = QRadioButton()
            self.rBtns.append(rbtn)
            rbtn.setText("")
            rbtn.setFixedWidth(20)
            rbtn.toggled.connect(
                partial(self.controller.onCoordinateSelected, i))
            lay_row.addWidget(rbtn)
            self.lay.addLayout(lay_row)
        if len(self.rBtns) > 0:
            self.rBtns[self.controller.selectedCoordinateIndex].blockSignals(
                True)
            self.rBtns[self.controller.selectedCoordinateIndex].setChecked(
                True)
            self.rBtns[self.controller.selectedCoordinateIndex].blockSignals(
                False)

    def onManualChoose(self, i, event):
        self.controller.rquestFrameCheckCoordinateColorManualChange(i)

    def updateCurrentColors(self, colors_img):
        num = min(len(colors_img), len(self.lblImageColors))
        for i in range(num):
            color = colors_img[i]
            self.lblImageColors[i].setStyleSheet(
                "background-color: rgb({},{},{});".format(
                    color[0], color[1], color[2]))

    def initConnectors(self):
        self.controller.onCurrentScreenColorsChanged.connect(
            self.updateCurrentColors)
        return
        # for i, rbtn in enumerate(self.rBtns):
        #   self.rbtn.toggled.connect(partial(self.controller.onCoordinateSelected, i))

    def changeData(self, new_data):
        self._clearLayout()
        self.initUI(new_data)
        if 'around' in new_data:
            if self.cBoxAround.currentIndex != new_data['around']:
                self._setAroundSafe(new_data['around'])

    def deleteLater(self):
        self.controller.onCurrentScreenColorsChanged.disconnect(
            self.updateCurrentColors)
        super(FrameCheckOption, self).deleteLater()
Beispiel #41
0
class SnapshotCompareWidget(QWidget):
    pvs_filtered = QtCore.pyqtSignal(set)
    restore_requested = QtCore.pyqtSignal(list)
    rgx_icon = None

    def __init__(self, snapshot, common_settings, parent=None, **kw):
        super().__init__(parent, **kw)
        self.snapshot = snapshot
        self.common_settings = common_settings

        # ----------- PV Table -------------
        # PV table consist of:
        #     self.model: holding the data, values, being updated by PV callbacks, etc
        #     self._proxy: a proxy model implementing the filter functionality
        #     self.view: visual representation of the PV table

        self.view = SnapshotPvTableView(self)
        self.view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.view.restore_requested.connect(self._handle_restore_request)

        self.model = SnapshotPvTableModel(snapshot, self)
        self.model.file_parse_errors.connect(self._show_snapshot_parse_errors)
        self._proxy = SnapshotPvFilterProxyModel(self)
        self._proxy.setSourceModel(self.model)
        self._proxy.filtered.connect(self.pvs_filtered)

        # Build model and set default visualization on view (column widths, etc)
        self.model.set_pvs(snapshot.pvs.values())
        self.view.setModel(self._proxy)

        # ---------- Filter control elements ---------------
        # - text input to filter by name
        # - drop down to filter by compare status
        # - check box to select if showing pvs with incomplete data

        if SnapshotCompareWidget.rgx_icon is None:
            SnapshotCompareWidget.rgx_icon = QIcon(
                os.path.join(os.path.dirname(os.path.realpath(__file__)),
                             "images/rgx.png"))

        # #### PV name filter
        pv_filter_label = QLabel("Filter:", self)
        pv_filter_label.setAlignment(Qt.AlignCenter | Qt.AlignRight)

        self.pv_filter_sel = QComboBox(self)
        self.pv_filter_sel.setEditable(True)
        self.pv_filter_sel.setIconSize(QtCore.QSize(35, 15))
        self.pv_filter_inp = self.pv_filter_sel.lineEdit()
        self.pv_filter_inp.setPlaceholderText("Filter by PV name")

        policy = self.pv_filter_sel.sizePolicy()
        policy.setHorizontalPolicy(policy.Expanding)
        self.pv_filter_sel.setSizePolicy(policy)

        self.pv_filter_sel.currentIndexChanged.connect(
            self._predefined_filter_selected)
        self.pv_filter_inp.textChanged.connect(self._create_name_filter)

        self._populate_filter_list()

        # Prepare pallets to color the pv name filter input if rgx not valid
        self._inp_palette_ok = self.pv_filter_inp.palette()
        self._inp_palette_err = QPalette()
        self._inp_palette_err.setColor(QPalette.Base, QColor("#F39292"))

        # Create a PV name filter layout and add items
        pv_filter_layout = QHBoxLayout()
        pv_filter_layout.setSpacing(10)
        pv_filter_layout.addWidget(pv_filter_label)
        pv_filter_layout.addWidget(self.pv_filter_sel)

        # #### Regex selector
        self.regex = QCheckBox("Regex", self)
        self.regex.stateChanged.connect(self._handle_regex_change)

        # #### Selector for comparison filter
        self.compare_filter_inp = QComboBox(self)
        self.compare_filter_inp.addItems(
            ["Show all", "Different only", "Equal only"])

        self.compare_filter_inp.currentIndexChanged.connect(
            self._proxy.set_eq_filter)
        self.compare_filter_inp.setMaximumWidth(200)

        # ### Show disconnected selector
        self.show_disconn_inp = QCheckBox("Show disconnected PVs.", self)
        self.show_disconn_inp.setChecked(True)
        self.show_disconn_inp.stateChanged.connect(
            self._proxy.set_disconn_filter)
        self.show_disconn_inp.setMaximumWidth(500)

        # Tolerance setting
        tol_label = QLabel("Tolerance:")
        tol = QSpinBox()
        tol.setRange(1, 1000000)
        tol.setValue(1)
        tol.valueChanged[int].connect(self.model.change_tolerance)
        self.model.change_tolerance(tol.value())

        # ### Put all tolerance and filter selectors in one layout
        filter_layout = QHBoxLayout()
        filter_layout.addWidget(tol_label)
        filter_layout.addWidget(tol)
        filter_layout.addWidget(make_separator(self, 'vertical'))

        filter_layout.addLayout(pv_filter_layout)
        filter_layout.addWidget(self.regex)

        filter_layout.addWidget(make_separator(self, 'vertical'))

        filter_layout.addWidget(self.compare_filter_inp)

        filter_layout.addWidget(self.show_disconn_inp)
        filter_layout.setAlignment(Qt.AlignLeft)
        filter_layout.setSpacing(10)

        # ------- Build main layout ---------
        layout = QVBoxLayout(self)
        layout.setContentsMargins(10, 10, 10, 10)
        layout.addLayout(filter_layout)
        layout.addWidget(self.view)
        self.setLayout(layout)

    def _populate_filter_list(self):
        predefined_filters = self.common_settings['predefined_filters']
        self.pv_filter_sel.blockSignals(True)
        self.pv_filter_sel.clear()
        self.pv_filter_sel.addItem(None)
        for rgx in predefined_filters.get('rgx-filters', list()):
            self.pv_filter_sel.addItem(SnapshotCompareWidget.rgx_icon, rgx)
        self.pv_filter_sel.addItems(predefined_filters.get('filters', list()))
        self.pv_filter_sel.blockSignals(False)

    def _handle_regex_change(self, state):
        txt = self.pv_filter_inp.text()
        if state and txt.strip() == '':
            self.pv_filter_inp.setText('.*')
        elif not state and txt.strip() == '.*':
            self.pv_filter_inp.setText('')
        else:
            self._create_name_filter(txt)

    def _create_name_filter(self, txt):
        if self.regex.isChecked():
            try:
                srch_filter = re.compile(txt)
                self.pv_filter_inp.setPalette(self._inp_palette_ok)
            except:
                # Syntax error (happens a lot during typing an expression). In such cases make compiler which will
                # not match any pv name
                srch_filter = re.compile("")
                self.pv_filter_inp.setPalette(self._inp_palette_err)
        else:
            srch_filter = txt
            self.pv_filter_inp.setPalette(self._inp_palette_ok)

        self._proxy.set_name_filter(srch_filter)

    def _show_snapshot_parse_errors(self, errors):
        show_snapshot_parse_errors(self, errors)

    def new_selected_files(self, selected_files):
        self.model.clear_snap_files()
        self.model.add_snap_files(selected_files)
        self._proxy.apply_filter()

    def clear_snap_files(self):
        self.model.clear_snap_files()

    def handle_new_snapshot_instance(self, snapshot):
        self.snapshot = snapshot
        self.model.snapshot = snapshot
        self.model.set_pvs(snapshot.pvs.values())
        self.view.sortByColumn(0, Qt.AscendingOrder)  # default sorting
        self._populate_filter_list()

    def _handle_restore_request(self, pvs_list):
        self.restore_requested.emit(pvs_list)

    def _predefined_filter_selected(self, idx):
        txt = self.pv_filter_inp.text()
        if idx == 0:
            # First empty option; the menu is always reset to this.
            return
        if not self.pv_filter_sel.itemIcon(idx).isNull():
            # Set back to first index, to get rid of the icon. Set to regex and
            # pass text of filter to the input
            self.pv_filter_sel.setCurrentIndex(0)
            self.regex.setChecked(True)
            self.pv_filter_inp.setText(txt)
        else:
            # Imitate same behaviour
            self.pv_filter_sel.setCurrentIndex(0)
            self.regex.setChecked(False)
            self.pv_filter_inp.setText(txt)

    def filter_update(self):
        self._proxy.apply_filter()
Beispiel #42
0
class tb_optical_model(QWidget):

	def __init__(self):
		QWidget.__init__(self)
		self.dump_dir=os.path.join(get_sim_path(),"light_dump")

		self.layout=QVBoxLayout()
		label=QLabel(_("Optical model")+":")
		self.layout.addWidget(label)

		self.cb = QComboBox()
		self.cb.activated.connect(self.on_cb_model_changed)
		self.layout.addWidget(self.cb)
		self.update()
		self.setLayout(self.layout)
		self.show()

	def get_text(self):
		out=self.cb.currentText()
		out=out.split(" ")[0]
		return out

	def file_name_set_start(self,start):
		self.start=start

	def file_name_set_end(self,end):
		self.end=end

	def find_models(self):
		ret=[]
		path=get_plugins_path()

		for file in glob.glob(os.path.join(path,"*")):
			file_name=os.path.basename(file)
			if file_name.startswith("light_"):
				if file_name.endswith(".dll") or file_name.endswith(".so"):
					ret.append(os.path.basename(file_name[6:]).split(".")[0])

		return ret

	def on_cb_model_changed(self):
		cb_text=self.cb.currentText()
		inp_update_token_value("light.inp", "#light_model", cb_text)
		
		
	def update(self):
		self.cb.blockSignals(True)

		self.cb.clear()
		models=self.find_models()
		if len(models)==0:
			error_dlg(self,_("I can't find any optical plugins, I think the model is not installed properly."))
			return

		for i in range(0, len(models)):
			self.cb.addItem(models[i])

		used_model=inp_get_token_value(os.path.join(get_sim_path(),"light.inp"), "#light_model")
		print(models,used_model)
		if models.count(used_model)==0:
			used_model="exp"
			inp_update_token_value(os.path.join(get_sim_path(),"light.inp"), "#light_model","exp")
			self.cb.setCurrentIndex(self.cb.findText(used_model))
		else:
			self.cb.setCurrentIndex(self.cb.findText(used_model))

		self.cb.blockSignals(False)
Beispiel #43
0
class PropertyWidget(QWidget):
    """display widget for tcam property"""
    def __init__(self, data: TcamCaptureData, prop: Prop):
        super().__init__()
        self.tcam = data.tcam
        self.signals = data.signals
        self.prop = prop
        self.setup_ui()

    def __repr__(self):
        return repr((self.prop.name, self.prop.valuetype, self.prop.category,
                     self.prop.group))

    def setup_ui(self):
        self.layout = QHBoxLayout()

        if self.prop.name != self.prop.group:
            self.spacer = QSpacerItem(30, 10)
            self.layout.addItem(self.spacer)

        self.setLayout(self.layout)
        if self.prop.valuetype != "boolean":
            self.name_label = QtWidgets.QLabel(self.prop.name)
            self.layout.addWidget(self.name_label)
        if self.prop.valuetype == "integer":
            self.value_label = QtWidgets.QLabel(str(self.prop.value))
            self.layout.addWidget(self.value_label)
            self.sld = QSlider(Qt.Horizontal, self)
            self.sld.setFocusPolicy(Qt.NoFocus)
            self.sld.setRange(self.prop.minval, self.prop.maxval)
            self.sld.setValue(self.prop.value)
            self.sld.setGeometry(30, 40, 100, 30)
            self.sld.valueChanged[int].connect(self.set_property)
            self.layout.addWidget(self.sld)
        elif self.prop.valuetype == "double":
            self.value_label = QtWidgets.QLabel(str(self.prop.value))
            self.layout.addWidget(self.value_label)
            self.sld = QSlider(Qt.Horizontal, self)
            self.sld.setFocusPolicy(Qt.NoFocus)
            self.sld.setRange(self.prop.minval * 1000, self.prop.maxval * 1000)
            self.sld.valueChanged[int].connect(self.set_property)
            self.sld.setGeometry(30, 40, 100, 30)
            self.layout.addWidget(self.sld)
        elif self.prop.valuetype == "button":
            self.checkbox = QPushButton(self)
            self.checkbox.clicked.connect(self.set_property)
            self.layout.addWidget(self.checkbox)
        elif self.prop.valuetype == "boolean":
            self.toggle = QPushButton(self.prop.name)
            self.toggle.setCheckable(True)
            if self.prop.value:
                self.toggle.toggle()
            self.toggle.toggled.connect(self.button_clicked)
            self.layout.addWidget(self.toggle)
        elif self.prop.valuetype == "string":
            pass
        elif self.prop.valuetype == "enum":
            self.combo = QComboBox(self)
            entry_list = self.tcam.get_tcam_menu_entries(self.prop.name)

            for e in entry_list:
                self.combo.addItem(e)
                self.combo.setCurrentText(self.prop.value)
                self.combo.currentIndexChanged['QString'].connect(
                    self.set_property)
                self.layout.addWidget(self.combo)

    def button_clicked(self):
        log.debug("button clicked")
        self.signals.change_property.emit(self.tcam, self.prop.name,
                                          self.toggle.isChecked(),
                                          self.prop.valuetype)

    def set_property(self, value):
        if self.prop.valuetype == "integer":
            self.value_label.setText(str(value))
        if self.prop.valuetype == "double":
            self.value_label.setText(str(value / 1000))
            self.signals.change_property.emit(self.tcam, self.prop.name,
                                              float(value) / 1000,
                                              self.prop.valuetype)
            return

        self.signals.change_property.emit(self.tcam, self.prop.name, value,
                                          self.prop.valuetype)

    def update(self, prop: Prop):
        self.prop = prop
        if self.prop.valuetype == "integer":
            self.value_label.setText(str(self.prop.value))
            self.sld.blockSignals(True)
            self.sld.setValue(self.prop.value)
            self.sld.blockSignals(False)
        elif self.prop.valuetype == "double":
            self.sld.blockSignals(True)
            self.value_label.setText("{:.3f}".format(self.prop.value))
            self.sld.setValue((self.prop.value * 1000))
            self.sld.blockSignals(False)

        elif self.prop.valuetype == "button":
            pass

        elif self.prop.valuetype == "boolean":

            if self.prop.value and not self.toggle.isChecked():
                self.toggle.blockSignals(True)
                self.toggle.toggle()
                self.toggle.blockSignals(False)

        elif self.prop.valuetype == "string":
            pass
        elif self.prop.valuetype == "enum":
            self.combo.blockSignals(True)
            self.combo.setCurrentText(prop.value)
            self.combo.blockSignals(False)
Beispiel #44
0
class PropertyWidget(QWidget):

    value_changed = pyqtSignal(object)

    """display widget for tcam property"""
    def __init__(self, data: TcamCaptureData, prop: Prop,
                 app_property: bool=False):
        super().__init__()
        self.app_property = app_property
        self.tcam = data.tcam
        self.signals = data.signals
        self.prop = prop
        self.setup_ui()

    def __repr__(self):
        return repr((self.prop.name, self.prop.valuetype,
                     self.prop.category, self.prop.group))

    def setup_ui(self):
        self.layout = QHBoxLayout()

        self.setLayout(self.layout)
        if self.prop.valuetype == "integer":
            self.sld = QSlider(Qt.Horizontal, self)
            self.sld.setFocusPolicy(Qt.NoFocus)
            try:
                self.sld.setRange(self.prop.minval, self.prop.maxval)
                self.sld.setValue(self.prop.value)
            except OverflowError:
                log.error("Property {} reported a range that could not be handled".format(self.prop.name))
            self.sld.setSingleStep(self.prop.step)
            self.sld.valueChanged[int].connect(self.set_property)
            self.layout.addWidget(self.sld)

            self.value_box = QSpinBox(self)
            try:
                self.value_box.setRange(self.prop.minval, self.prop.maxval)
            except OverflowError:
                log.error("Property {} reported a range that could not be handled".format(self.prop.name))
            self.value_box.setSingleStep(self.prop.step)
            self.value_box.setValue(self.prop.value)
            self.value_box.valueChanged[int].connect(self.set_property_box)
            self.value_box.setKeyboardTracking(False)
            self.layout.addWidget(self.value_box)

        elif self.prop.valuetype == "double":
            self.sld = QSlider(Qt.Horizontal, self)
            self.sld.setFocusPolicy(Qt.NoFocus)
            try:
                self.sld.setRange(self.prop.minval, self.prop.maxval)
                self.sld.setValue(self.prop.value)
            except OverflowError:
                log.error("Property {} reported a range that could not be handled".format(self.prop.name))
            self.sld.setSingleStep(self.prop.step * 1000)
            self.sld.valueChanged[int].connect(self.set_property)
            self.sld.setGeometry(30, 40, 100, 30)
            self.layout.addWidget(self.sld)

            self.value_box = QDoubleSpinBox(self)
            try:
                self.value_box.setRange(self.prop.minval, self.prop.maxval)
            except OverflowError:
                log.error("Property {} reported a range that could not be handled".format(self.prop.name))
            self.value_box.setSingleStep(self.prop.step)
            self.value_box.setValue(self.prop.value)
            self.value_box.valueChanged[float].connect(self.set_property_box)
            self.value_box.setKeyboardTracking(False)
            self.layout.addWidget(self.value_box)

        elif self.prop.valuetype == "button":
            self.checkbox = QPushButton(self)
            self.checkbox.clicked.connect(self.set_property)
            self.layout.addWidget(self.checkbox)
        elif self.prop.valuetype == "boolean":
            self.toggle = QCheckBox(self)
            self.toggle.setCheckable(True)
            if self.prop.value:
                self.toggle.toggle()
            self.toggle.toggled.connect(self.button_clicked)
            self.layout.addWidget(self.toggle)
        elif self.prop.valuetype == "string":
            pass
        elif self.prop.valuetype == "enum":
            self.combo = QComboBox(self)
            entry_list = self.tcam.get_tcam_menu_entries(self.prop.name)

            for e in entry_list:
                self.combo.addItem(e)
                self.combo.setCurrentText(self.prop.value)
                self.combo.currentIndexChanged['QString'].connect(self.set_property)
                self.layout.addWidget(self.combo)

    def button_clicked(self):
        log.debug("button clicked")
        self.signals.change_property.emit(self.tcam, self.prop.name,
                                          self.toggle.isChecked(), self.prop.valuetype)
        self.value_changed.emit(self)

    def set_property(self, value, emit_value_changed=True):
        self.prop.value = value
        if self.prop.valuetype == "integer":
            self.update_box_value(self.value_box, value)

        if self.prop.valuetype == "double":
            self.update_box_value(self.value_box, value)

            self.signals.change_property.emit(self.tcam, self.prop.name,
                                              float(value), self.prop.valuetype)
            return

        self.signals.change_property.emit(self.tcam, self.prop.name,
                                          value, self.prop.valuetype)
        if emit_value_changed:
            self.value_changed.emit(self)

    def set_property_box(self, value):
        if self.prop.valuetype == "integer":
            self.update_slider_value(self.sld, value)

        if self.prop.valuetype == "double":
            self.update_slider_value(self.sld, value)

            self.signals.change_property.emit(self.tcam, self.prop.name,
                                              float(value), self.prop.valuetype)
            return

        self.signals.change_property.emit(self.tcam, self.prop.name,
                                          value, self.prop.valuetype)
        self.value_changed.emit(self)

    def update_box_value(self, box, value):
        box.blockSignals(True)
        box.setValue(value)
        box.blockSignals(False)

    def update_box_range(self, box, minval, maxval):
        """"""
        box.blockSignals(True)
        box.setRange(self.prop.minval,
                     self.prop.maxval)
        box.blockSignals(False)

    def update_slider_value(self, slider, value):
        slider.blockSignals(True)
        try:
            slider.setValue(value)
        except OverflowError:
            log.error("A slider had a value outside of the integer range. That should no happen.")
        finally:
            slider.blockSignals(False)

    def update_slider_range(self, slider, minval, maxval):
        """"""
        self.sld.blockSignals(True)
        try:
            self.sld.setRange(self.prop.minval,
                              self.prop.maxval)
        except OverflowError:
            log.error("A slider had a value outside of the integer range. That should no happen.")
        finally:
            self.sld.blockSignals(False)

    def update(self, prop: Prop):

        emit_value_changed = False

        if self.prop.value != prop.value:
            emit_value_changed = True

        self.prop = prop
        if self.prop.valuetype == "integer":
            self.update_slider_value(self.sld, self.prop.value)

            self.update_slider_range(self.sld,
                                     self.prop.minval,
                                     self.prop.maxval)
            self.update_box_range(self.value_box,
                                  self.prop.minval,
                                  self.prop.maxval)
            self.update_box_value(self.value_box, self.prop.value)
        elif self.prop.valuetype == "double":
            self.update_slider_range(self.sld,
                                     self.prop.minval,
                                     self.prop.maxval)
            self.update_slider_value(self.sld, self.prop.value)
            self.update_box_range(self.value_box,
                                  self.prop.minval,
                                  self.prop.maxval)
            self.update_box_value(self.value_box, self.prop.value)

        elif self.prop.valuetype == "button":
            pass

        elif self.prop.valuetype == "boolean":

            if self.prop.value and not self.toggle.isChecked():
                self.toggle.blockSignals(True)
                self.toggle.toggle()
                self.toggle.blockSignals(False)

        elif self.prop.valuetype == "string":
            pass
        elif self.prop.valuetype == "enum":
            self.combo.blockSignals(True)
            self.combo.setCurrentText(prop.value)
            self.combo.blockSignals(False)

        if emit_value_changed:
            self.value_changed.emit(self)

    def reset(self):
        if self.prop.valuetype == "integer":
            self.update_box_value(self.value_box, self.prop.defval)
            self.sld.setValue(self.prop.defval)

        elif self.prop.valuetype == "double":
            self.update_box_value(self.value_box, self.prop.defval)
            self.sld.setValue(self.prop.defval * 1000)

        elif self.prop.valuetype == "button":
            pass

        elif self.prop.valuetype == "boolean":
            if self.prop.defval and not self.toggle.isChecked():
                self.toggle.toggle()

        elif self.prop.valuetype == "string":
            pass
        elif self.prop.valuetype == "enum":
            self.combo.setCurrentText(self.prop.defval)
        self.value_changed.emit(self)
Beispiel #45
0
class HistoryManagerWidget(QWidget):

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

        self.listHistory = []
        self.nam = QtNetwork.QNetworkAccessManager()

        self.setting = QSettings()

        self.searchLineEdit = QLineEdit()
        self.tableView = QTableView()
        self.columnComboBox = QComboBox()
        self.searchLabel = QLabel()
        self.searchLabel.setText("Filter")

        self.model = QStandardItemModel(self)

        searchHbox = QHBoxLayout()
        searchHbox.addWidget(self.searchLabel)
        searchHbox.addWidget(self.searchLineEdit)
        searchHbox.addWidget(self.columnComboBox)

        self.header = "Order ID;Order Status;Card ID;Menu ID;Menu Name;Price;Qty;" \
                 "Item Status;Table Number;Order Time;Modified Time".split(";")
        self.model.setHorizontalHeaderLabels(self.header)
        self.tableView.horizontalHeader().setStretchLastSection(True)

        hboxLayout = QHBoxLayout()
        self.backButton = QPushButton()
        self.backButton.setText("Back")

        self.refreshButton = QPushButton()
        self.refreshButton.setText("Refresh")
        self.refreshButton.clicked.connect(self.refresh)

        self.saveCSVButton = QPushButton()
        self.saveCSVButton.setText("Save as CSV")
        self.saveCSVButton.clicked.connect(self.saveCSV)

        hboxLayout.addWidget(self.backButton)
        hboxLayout.addWidget(self.refreshButton)
        hboxLayout.addWidget(self.saveCSVButton)

        widgetTitleLabel = QLabel()
        widgetTitleLabel.setAlignment(Qt.AlignCenter)
        widgetTitleLabel.setText("History Manager")

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(widgetTitleLabel)
        mainLayout.addLayout(searchHbox)
        mainLayout.addWidget(self.tableView)
        mainLayout.addLayout(hboxLayout)

        self.proxy = QSortFilterProxyModel(self)
        self.proxy.setSourceModel(self.model)

        self.tableView.setModel(self.proxy)
        self.columnComboBox.addItems(self.header)

        self.searchLineEdit.textChanged.connect(self.on_lineEdit_textChanged)
        self.columnComboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged)

        self.horizontalHeader = self.tableView.horizontalHeader()

        self.setLayout(mainLayout)

    def saveCSV(self):
        data = ""
        rows = self.model.rowCount()
        columns = self.model.columnCount()

        if rows>0:
            for title in self.header:
                data += title
                data += ","
            data += "\n"
            for i in range(rows):
                for j in range(columns):
                    index = self.model.index(i,j)
                    # print(str(self.model.data(index)))
                    data += str(self.model.data(index))
                    data += ","
                data += "\n"

            name, _ = QFileDialog.getSaveFileName(self, 'Save File', "History SELFO.csv", "csv(*.csv)")
            if name:
                file = open(name, 'w')
                file.write(data)
                file.close()
        else:
            QMessageBox.critical(self, "Error", "No Data")

    def clear(self):
        self.listHistory.clear()
        self.model.clear()
        self.model.setHorizontalHeaderLabels(self.header)

    def refresh(self):
        self.clear()
        self.doRequestOrderDetail()

    def populateList(self):
        for rowName in range(len(self.listHistory)):
            self.model.invisibleRootItem().appendRow(
                [QStandardItem("{}".format(self.listHistory[rowName][column]))
                 for column in range(len(self.header))
                 ]
            )
        self.tableView.resizeColumnsToContents()

    def closeHistoryManager(self):
        self.mainWindow.stackedWidget.removeWidget(self)

    def doRequestOrderDetail(self):
        url = self.setting.value("baseURL", "")
        url += "/orderdetail/?sellerID=" + str(self.setting.value("sellerID", "")) \
               # + "&itemStatus=" + "placed"
        req = QtNetwork.QNetworkRequest(QUrl(url))

        reply = self.nam.get(req)
        reply.finished.connect(self.handleResponseOrderDetail)

    def handleResponseOrderDetail(self):
        reply = self.sender()

        er = reply.error()

        if er == QtNetwork.QNetworkReply.NoError:

            bytes_string = reply.readAll()
            data = json.loads(str(bytes_string, 'utf-8'))
            # print(data)

            for history in data:
                # id = history['id']
                orderID = history['orderID']
                orderStatus = history['orderStatus']
                cardID = history['cardID']
                # sellerID = history['sellerID']
                menuID = history['menuID']
                menuName = history['menuName']
                itemStatus = history['itemStatus']
                price = formatRupiah(history['price'])
                qty = history['qty']
                tableNumber = history['tableNumber']
                rawOrderTime = history['orderTime']
                orderTime = datetime.datetime.strptime(
                    rawOrderTime, "%Y-%m-%dT%H:%M:%S.%f+07:00").strftime("%d %b %Y %H:%M:%S")
                rawModifiedTime = history['modifiedTime']
                if rawModifiedTime is not None:
                    modifiedTime = datetime.datetime.strptime(
                        rawModifiedTime, "%Y-%m-%dT%H:%M:%S.%f+07:00").strftime("%d %b %Y %H:%M:%S")
                else:
                    modifiedTime = "null"
                historyItem = [orderID, orderStatus, cardID, menuID, menuName, price, qty, itemStatus, tableNumber, orderTime, modifiedTime]
                self.listHistory.append(historyItem)

            self.populateList()

        else:
            errorMessage = "Error occured: " + str(er) + "\n" + str(reply.errorString())
            QMessageBox.critical(self, "Error Order Detail", errorMessage)
        reply.deleteLater()

    def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
        self.logicalIndex   = logicalIndex
        self.menuValues     = QMenu(self)
        self.signalMapper   = QSignalMapper(self)

        self.columnComboBox.blockSignals(True)
        self.columnComboBox.setCurrentIndex(self.logicalIndex)
        self.columnComboBox.blockSignals(True)

        valuesUnique = [    self.model.item(row, self.logicalIndex).text()
                            for row in range(self.model.rowCount())
                            ]

        actionAll = QAction("All", self)
        actionAll.triggered.connect(self.on_actionAll_triggered)
        self.menuValues.addAction(actionAll)
        self.menuValues.addSeparator()

        for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):
            action = QAction(actionName, self)
            self.signalMapper.setMapping(action, actionNumber)
            action.triggered.connect(self.signalMapper.map)
            self.menuValues.addAction(action)

        self.signalMapper.mapped.connect(self.on_signalMapper_mapped)

        headerPos = self.tableView.mapToGlobal(self.horizontalHeader.pos())

        posY = headerPos.y() + self.horizontalHeader.height()
        posX = headerPos.x() + self.horizontalHeader.sectionPosition(self.logicalIndex)

        self.menuValues.exec_(QPoint(posX, posY))

    def on_actionAll_triggered(self):
        filterColumn = self.logicalIndex
        filterString = QRegExp(  "",
                                        Qt.CaseInsensitive,
                                        QRegExp.RegExp
                                        )

        self.proxy.setFilterRegExp(filterString)
        self.proxy.setFilterKeyColumn(filterColumn)

    def on_signalMapper_mapped(self, i):
        stringAction = self.signalMapper.mapping(i).text()
        filterColumn = self.logicalIndex
        filterString = QRegExp(  stringAction,
                                        Qt.CaseSensitive,
                                        QRegExp.FixedString
                                        )

        self.proxy.setFilterRegExp(filterString)
        self.proxy.setFilterKeyColumn(filterColumn)

    def on_lineEdit_textChanged(self, text):
        search = QRegExp(    text,
                                    Qt.CaseInsensitive,
                                    QRegExp.RegExp
                                    )

        self.proxy.setFilterRegExp(search)

    def on_comboBox_currentIndexChanged(self, index):
        self.proxy.setFilterKeyColumn(index)
Beispiel #46
0
class BasemapRenderingOptionsWidget(QFrame):

    values_changed = pyqtSignal()

    def __init__(self, datatype=None):
        super().__init__()
        self.layout = QGridLayout()
        self.layout.setMargin(0)

        self.labelProc = QLabel("Processing:")
        self.comboProc = QComboBox()
        self.layout.addWidget(self.labelProc, 0, 0)
        self.layout.addWidget(self.comboProc, 0, 1)

        self.load_ramps()
        self.labelRamp = QLabel("Color ramp:")
        self.comboRamp = QComboBox()

        self.layout.addWidget(self.labelRamp, 1, 0)
        self.layout.addWidget(self.comboRamp, 1, 1)

        self.setLayout(self.layout)
        self.comboProc.currentIndexChanged.connect(self._proc_changed)
        self.listWidget = QListWidget()
        self.comboRamp.setView(self.listWidget)
        self.comboRamp.setModel(self.listWidget.model())
        self.comboRamp.currentIndexChanged.connect(self.values_changed.emit)

        self.set_datatype(datatype)

        self.setStyleSheet("QFrame {border: 0px;}")

    def set_datatype(self, datatype):
        self.datatype = datatype
        self.comboRamp.blockSignals(True)
        self.comboProc.clear()
        self.comboProc.addItem("default")
        procs = self.processes_for_datatype()
        if procs:
            self.comboProc.addItems(procs)
        self.labelProc.setVisible(self.can_use_indices())
        self.comboProc.setVisible(self.can_use_indices())
        self.comboRamp.blockSignals(False)
        self.comboRamp.setVisible(self.can_use_indices())
        self.labelRamp.setVisible(self.can_use_indices())
        self._proc_changed()

    def _proc_changed(self):
        if self.can_use_indices():
            self.comboRamp.clear()
            self.comboRamp.setIconSize(QSize(100, 20))
            default, ramps = self.ramps_for_current_process()
            if ramps:
                self.comboRamp.setVisible(True)
                self.labelRamp.setVisible(True)
                for name in ramps:
                    icon = self.ramp_pixmaps[name]
                    self.comboRamp.addItem(name)
                    self.comboRamp.setItemData(self.comboRamp.count() - 1,
                                               icon, Qt.DecorationRole)
                self.comboRamp.setCurrentText(default)
                if len(ramps) != len(list(self.ramps["colors"].keys())):
                    item = QListWidgetItem()
                    self.listWidget.addItem(item)
                    label = QLabel(
                        "<a href='#' style='color: grey;'>Show all ramps</a>")
                    label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
                    label.linkActivated.connect(self._show_all_ramps)
                    self.listWidget.setItemWidget(item, label)
            else:
                self.comboRamp.setVisible(False)
                self.labelRamp.setVisible(False)
                self.values_changed.emit()
        else:
            self.values_changed.emit()

    def _show_all_ramps(self):
        self.comboRamp.clear()
        self.comboRamp.setIconSize(QSize(100, 20))
        ramps = list(self.ramps["colors"].keys())
        for name in ramps:
            icon = self.ramp_pixmaps[name]
            self.comboRamp.addItem(name)
            self.comboRamp.setItemData(self.comboRamp.count() - 1, icon,
                                       Qt.DecorationRole)
        self.comboRamp.showPopup()

    def ramps_for_current_process(self):
        process = self.comboProc.currentText()
        if process in self.ramps["indices"]:
            pref_colors = self.ramps["indices"][process][
                "pref-colors"] or list(self.ramps["colors"].keys())
            return self.ramps["indices"][process]["color"], pref_colors
        else:
            return None, []

    def load_ramps(self):
        path = os.path.join(os.path.dirname(os.path.dirname(__file__)),
                            "resources", "mosaics_caps.json")
        with open(path) as f:
            self.ramps = json.load(f)

        self.ramp_pixmaps = {}
        for k, v in self.ramps["colors"].items():
            base64 = v["icon"][len("data:image/png;base64,"):].encode()
            byte_array = QByteArray.fromBase64(base64)
            image = QImage.fromData(byte_array, "PNG")
            scaled = image.scaled(100, 20)
            pixmap = QPixmap.fromImage(scaled)
            self.ramp_pixmaps[k] = pixmap

    def processes_for_datatype(self):
        if self.datatype == "uint16":
            return [
                "rgb", "cir", "ndvi", "mtvi2", "ndwi", "msavi2", "tgi", "vari"
            ]
        else:
            return []

    def can_use_indices(self):
        return self.datatype == "uint16"

    def process(self):
        return self.comboProc.currentText()

    def set_process(self, proc):
        self.comboProc.setCurrentText(proc)

    def set_ramp(self, ramp):
        self.comboRamp.setCurrentText(ramp)

    def ramp(self):
        ramp = self.comboRamp.currentText() if self.can_use_indices() else ""
        return ramp
Beispiel #47
0
class SchemeSelector(QWidget):

    currentChanged = pyqtSignal()
    changed = pyqtSignal()

    def __init__(self, parent=None):
        super(SchemeSelector, self).__init__(parent)
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.label = QLabel()
        self.scheme = QComboBox()
        self.menuButton = QPushButton(flat=True)
        menu = QMenu(self.menuButton)
        self.menuButton.setMenu(menu)
        layout.addWidget(self.label)
        layout.addWidget(self.scheme)
        layout.addWidget(self.menuButton)
        layout.addStretch(1)

        # action generator
        def act(slot, icon=None):
            a = QAction(self, triggered=slot)
            self.addAction(a)
            icon and a.setIcon(icons.get(icon))
            return a

        # add action
        a = self.addAction_ = act(self.slotAdd, 'list-add')
        menu.addAction(a)

        # remove action
        a = self.removeAction = act(self.slotRemove, 'list-remove')
        menu.addAction(a)

        # rename action
        a = self.renameAction = act(self.slotRename, 'document-edit')
        menu.addAction(a)

        menu.addSeparator()

        # import action
        a = self.importAction = act(self.slotImport, 'document-open')
        menu.addAction(a)

        # export action
        a = self.exportAction = act(self.slotExport, 'document-save-as')
        menu.addAction(a)

        self.scheme.currentIndexChanged.connect(self.slotSchemeChanged)
        app.translateUI(self)

    def translateUI(self):
        self.label.setText(_("Scheme:"))
        self.menuButton.setText(_("&Menu"))
        self.addAction_.setText(_("&Add..."))
        self.removeAction.setText(_("&Remove"))
        self.renameAction.setText(_("Re&name..."))
        self.importAction.setText(_("&Import..."))
        self.exportAction.setText(_("&Export..."))

    def slotSchemeChanged(self, index):
        """Called when the Scheme combobox is changed by the user."""
        self.disableDefault(self.scheme.itemData(index) == 'default')
        self.currentChanged.emit()
        self.changed.emit()

    def disableDefault(self, val):
        self.removeAction.setDisabled(val)
        self.renameAction.setDisabled(val)

    def schemes(self):
        """Returns the list with internal names of currently available schemes."""
        return [self.scheme.itemData(i) for i in range(self.scheme.count())]

    def currentScheme(self):
        """Returns the internal name of the currently selected scheme"""
        return self.scheme.itemData(self.scheme.currentIndex())

    def insertSchemeItem(self, name, scheme):
        for i in range(1, self.scheme.count()):
            n = self.scheme.itemText(i)
            if n.lower() > name.lower():
                self.scheme.insertItem(i, name, scheme)
                break
        else:
            self.scheme.addItem(name, scheme)

    def addScheme(self, name):
        num, key = 1, 'user1'
        while key in self.schemes() or key in self._schemesToRemove:
            num += 1
            key = 'user{0}'.format(num)
        self.insertSchemeItem(name, key)
        self.scheme.setCurrentIndex(self.scheme.findData(key))
        return key

    def slotAdd(self):
        name, ok = QInputDialog.getText(
            self, app.caption(_("Add Scheme")),
            _("Please enter a name for the new scheme:"))
        if ok:
            self.addScheme(name)

    def slotRemove(self):
        index = self.scheme.currentIndex()
        scheme = self.scheme.itemData(index)
        if scheme == 'default':
            return  # default can not be removed

        self._schemesToRemove.add(scheme)
        self.scheme.removeItem(index)

    def slotRename(self):
        index = self.scheme.currentIndex()
        name = self.scheme.itemText(index)
        scheme = self.scheme.itemData(index)
        newName, ok = QInputDialog.getText(self,
                                           _("Rename"),
                                           _("New name:"),
                                           text=name)
        if ok:
            self.scheme.blockSignals(True)
            self.scheme.removeItem(index)
            self.insertSchemeItem(newName, scheme)
            self.scheme.setCurrentIndex(self.scheme.findData(scheme))
            self.scheme.blockSignals(False)
            self.changed.emit()

    def slotImport(self):
        filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"),
                                                  _("All Files"))
        caption = app.caption(_("dialog title", "Import color theme"))
        filename = QFileDialog.getOpenFileName(self, caption, QDir.homePath(),
                                               filetypes)[0]
        if filename:
            self.parent().import_(filename)

    def slotExport(self):
        name = self.scheme.currentText()
        filetypes = "{0} (*.xml);;{1} (*)".format(_("XML Files"),
                                                  _("All Files"))
        caption = app.caption(
            _("dialog title", "Export {name}").format(name=name))
        path = os.path.join(QDir.homePath(), name + '.xml')
        filename = QFileDialog.getSaveFileName(self, caption, path,
                                               filetypes)[0]
        if filename:
            if os.path.splitext(filename)[1] != '.xml':
                filename += '.xml'
            self.parent().export(name, filename)

    def loadSettings(self, currentKey, namesGroup):
        # don't mark schemes for removal anymore
        self._schemesToRemove = set()

        s = QSettings()
        cur = s.value(currentKey, "default", str)

        # load the names for the shortcut schemes
        s.beginGroup(namesGroup)
        block = self.scheme.blockSignals(True)
        self.scheme.clear()
        self.scheme.addItem(_("Default"), "default")
        lst = [(s.value(key, key, str), key) for key in s.childKeys()]
        for name, key in sorted(lst, key=lambda f: f[0].lower()):
            self.scheme.addItem(name, key)

        # find out index
        index = self.scheme.findData(cur)
        self.disableDefault(cur == 'default')
        self.scheme.setCurrentIndex(index)
        self.scheme.blockSignals(block)
        self.currentChanged.emit()

    def saveSettings(self, currentKey, namesGroup, removePrefix=None):
        # first save new scheme names
        s = QSettings()
        s.beginGroup(namesGroup)
        for i in range(self.scheme.count()):
            if self.scheme.itemData(i) != 'default':
                s.setValue(self.scheme.itemData(i), self.scheme.itemText(i))

        for scheme in self._schemesToRemove:
            s.remove(scheme)
        s.endGroup()
        if removePrefix:
            for scheme in self._schemesToRemove:
                s.remove("{0}/{1}".format(removePrefix, scheme))
        # then save current
        scheme = self.currentScheme()
        s.setValue(currentKey, scheme)
        # clean up
        self._schemesToRemove = set()
Beispiel #48
0
class LedgerAuthDialog(QDialog):
    def __init__(self, handler, data):
        '''Ask user for 2nd factor authentication. Support text, security card and paired mobile methods.
        Use last method from settings, but support new pairing and downgrade.
        '''
        QDialog.__init__(self, handler.top_level_window())
        self.handler = handler
        self.txdata = data
        self.idxs = self.txdata[
            'keycardData'] if self.txdata['confirmationType'] > 1 else ''
        self.setMinimumWidth(650)
        self.setWindowTitle(_("Ledger Wallet Authentication"))
        self.cfg = copy.deepcopy(self.handler.win.wallet.get_keystore().cfg)
        self.dongle = self.handler.win.wallet.get_keystore().get_client(
        ).dongle
        self.ws = None
        self.pin = ''

        self.devmode = self.getDevice2FAMode()
        if self.devmode == 0x11 or self.txdata['confirmationType'] == 1:
            self.cfg['mode'] = 0

        vbox = QVBoxLayout()
        self.setLayout(vbox)

        def on_change_mode(idx):
            if idx < 2 and self.ws:
                self.ws.stop()
                self.ws = None
            self.cfg[
                'mode'] = 0 if self.devmode == 0x11 else idx if idx > 0 else 1
            if self.cfg['mode'] > 1 and self.cfg['pair'] and not self.ws:
                self.req_validation()
            if self.cfg['mode'] > 0:
                self.handler.win.wallet.get_keystore().cfg = self.cfg
                self.handler.win.wallet.save_keystore()
            self.update_dlg()

        def add_pairing():
            self.do_pairing()

        def return_pin():
            self.pin = self.pintxt.text(
            ) if self.txdata['confirmationType'] == 1 else self.cardtxt.text()
            if self.cfg['mode'] == 1:
                self.pin = ''.join(chr(int(str(i), 16)) for i in self.pin)
            self.accept()

        self.modebox = QWidget()
        modelayout = QHBoxLayout()
        self.modebox.setLayout(modelayout)
        modelayout.addWidget(QLabel(_("Method:")))
        self.modes = QComboBox()
        modelayout.addWidget(self.modes, 2)
        self.addPair = QPushButton(_("Pair"))
        self.addPair.setMaximumWidth(60)
        modelayout.addWidget(self.addPair)
        modelayout.addStretch(1)
        self.modebox.setMaximumHeight(50)
        vbox.addWidget(self.modebox)

        self.populate_modes()
        self.modes.currentIndexChanged.connect(on_change_mode)
        self.addPair.clicked.connect(add_pairing)

        self.helpmsg = QTextEdit()
        self.helpmsg.setStyleSheet(
            "QTextEdit { background-color: lightgray; }")
        self.helpmsg.setReadOnly(True)
        vbox.addWidget(self.helpmsg)

        self.pinbox = QWidget()
        pinlayout = QHBoxLayout()
        self.pinbox.setLayout(pinlayout)
        self.pintxt = QLineEdit()
        self.pintxt.setEchoMode(2)
        self.pintxt.setMaxLength(4)
        self.pintxt.returnPressed.connect(return_pin)
        pinlayout.addWidget(QLabel(_("Enter PIN:")))
        pinlayout.addWidget(self.pintxt)
        pinlayout.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        pinlayout.addStretch(1)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        vbox.addWidget(self.pinbox)

        self.cardbox = QWidget()
        card = QVBoxLayout()
        self.cardbox.setLayout(card)
        self.addrtext = QTextEdit()
        self.addrtext.setStyleSheet(
            "QTextEdit { color:blue; background-color:lightgray; padding:15px 10px; border:none; font-size:20pt; font-family:monospace; }"
        )
        self.addrtext.setReadOnly(True)
        self.addrtext.setMaximumHeight(130)
        card.addWidget(self.addrtext)

        def pin_changed(s):
            if len(s) < len(self.idxs):
                i = self.idxs[len(s)]
                addr = self.txdata['address']
                if not constants.net.TESTNET:
                    text = addr[:i] + '<u><b>' + addr[
                        i:i + 1] + '</u></b>' + addr[i + 1:]
                else:
                    # pin needs to be created from mainnet address
                    addr_mainnet = bitcoin.script_to_address(
                        bitcoin.address_to_script(addr),
                        net=constants.BitcoinMainnet)
                    addr_mainnet = addr_mainnet[:i] + '<u><b>' + addr_mainnet[
                        i:i + 1] + '</u></b>' + addr_mainnet[i + 1:]
                    text = str(addr) + '\n' + str(addr_mainnet)
                self.addrtext.setHtml(str(text))
            else:
                self.addrtext.setHtml(_("Press Enter"))

        pin_changed('')
        cardpin = QHBoxLayout()
        cardpin.addWidget(QLabel(_("Enter PIN:")))
        self.cardtxt = QLineEdit()
        self.cardtxt.setEchoMode(2)
        self.cardtxt.setMaxLength(len(self.idxs))
        self.cardtxt.textChanged.connect(pin_changed)
        self.cardtxt.returnPressed.connect(return_pin)
        cardpin.addWidget(self.cardtxt)
        cardpin.addWidget(QLabel(_("NOT DEVICE PIN - see above")))
        cardpin.addStretch(1)
        card.addLayout(cardpin)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        vbox.addWidget(self.cardbox)

        self.pairbox = QWidget()
        pairlayout = QVBoxLayout()
        self.pairbox.setLayout(pairlayout)
        pairhelp = QTextEdit(helpTxt[5])
        pairhelp.setStyleSheet("QTextEdit { background-color: lightgray; }")
        pairhelp.setReadOnly(True)
        pairlayout.addWidget(pairhelp, 1)
        self.pairqr = QRCodeWidget()
        pairlayout.addWidget(self.pairqr, 4)
        self.pairbox.setVisible(False)
        vbox.addWidget(self.pairbox)
        self.update_dlg()

        if self.cfg['mode'] > 1 and not self.ws:
            self.req_validation()

    def populate_modes(self):
        self.modes.blockSignals(True)
        self.modes.clear()
        self.modes.addItem(
            _("Summary Text PIN (requires dongle replugging)"
              ) if self.txdata['confirmationType'] ==
            1 else _("Summary Text PIN is Disabled"))
        if self.txdata['confirmationType'] > 1:
            self.modes.addItem(_("Security Card Challenge"))
            if not self.cfg['pair']:
                self.modes.addItem(_("Mobile - Not paired"))
            else:
                self.modes.addItem(
                    _("Mobile - {}").format(self.cfg['pair'][1]))
        self.modes.blockSignals(False)

    def update_dlg(self):
        self.modes.setCurrentIndex(self.cfg['mode'])
        self.modebox.setVisible(True)
        self.addPair.setText(
            _("Pair") if not self.cfg['pair'] else _("Re-Pair"))
        self.addPair.setVisible(self.txdata['confirmationType'] > 2)
        self.helpmsg.setText(
            helpTxt[self.cfg['mode'] if self.cfg['mode'] < 2 else 2 if self.
                    cfg['pair'] else 4])
        self.helpmsg.setMinimumHeight(180 if self.txdata['confirmationType'] ==
                                      1 else 100)
        self.pairbox.setVisible(False)
        self.helpmsg.setVisible(True)
        self.pinbox.setVisible(self.cfg['mode'] == 0)
        self.cardbox.setVisible(self.cfg['mode'] == 1)
        self.pintxt.setFocus(
            True) if self.cfg['mode'] == 0 else self.cardtxt.setFocus(True)
        self.setMaximumHeight(400)

    def do_pairing(self):
        rng = os.urandom(16)
        pairID = (hexlify(rng) +
                  hexlify(hashlib.sha256(rng).digest()[0:1])).decode('utf-8')
        self.pairqr.setData(pairID)
        self.modebox.setVisible(False)
        self.helpmsg.setVisible(False)
        self.pinbox.setVisible(False)
        self.cardbox.setVisible(False)
        self.pairbox.setVisible(True)
        self.pairqr.setMinimumSize(300, 300)
        if self.ws:
            self.ws.stop()
        self.ws = LedgerWebSocket(self, pairID)
        self.ws.pairing_done.connect(self.pairing_done)
        self.ws.start()

    def pairing_done(self, data):
        if data is not None:
            self.cfg['pair'] = [data['pairid'], data['name'], data['platform']]
            self.cfg['mode'] = 2
            self.handler.win.wallet.get_keystore().cfg = self.cfg
            self.handler.win.wallet.save_keystore()
        self.pin = 'paired'
        self.accept()

    def req_validation(self):
        if self.cfg['pair'] and 'secureScreenData' in self.txdata:
            if self.ws:
                self.ws.stop()
            self.ws = LedgerWebSocket(self, self.cfg['pair'][0], self.txdata)
            self.ws.req_updated.connect(self.req_updated)
            self.ws.start()

    def req_updated(self, pin):
        if pin == 'accepted':
            self.helpmsg.setText(helpTxt[3])
        else:
            self.pin = str(pin)
            self.accept()

    def getDevice2FAMode(self):
        apdu = [0xe0, 0x24, 0x01, 0x00, 0x00, 0x01]  # get 2fa mode
        try:
            mode = self.dongle.exchange(bytearray(apdu))
            return mode
        except BTChipException as e:
            debug_msg('Device getMode Failed')
        return 0x11

    def closeEvent(self, evnt):
        debug_msg("CLOSE - Stop WS")
        if self.ws:
            self.ws.stop()
        if self.pairbox.isVisible():
            evnt.ignore()
            self.update_dlg()
Beispiel #49
0
class FilterableTable(SQLTable):
    """a filterable Table Widget that displays content of an SQLite table;
    for individual widgets, subclass 
     and overwrite the create_model method;
    add_color_proxy should be an (INT allele_status-column, INT lab_status-column) tuple
    """
    def __init__(self, log, mydb = ": memory :", add_color_proxy = False, header_dic = None):
        super().__init__(log, mydb)
        self.add_color_proxy = add_color_proxy
        self.header_dic = header_dic
        self.create_model()
        self.fill_UI()
        self.create_filter_model()
        self.update_filterbox()
        
    def fill_UI(self):
        """sets up the layout
        """
        self.log.debug("\t- Setting up the table...")
        self.table = QTableView()
        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.header = self.table.horizontalHeader() # table header
        self.header.setSectionResizeMode(QHeaderView.ResizeToContents)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setAlternatingRowColors(True)
#         self.header.sectionClicked.connect(self.on_header_sectionClicked)
        
        mode = QAbstractItemView.SingleSelection
        self.table.setSelectionMode(mode)
        
        self.grid.addWidget(self.table, 2, 0, 10, 10)

        self.filter_lbl = QLabel("Filter:", self)
        self.grid.addWidget(self.filter_lbl, 1, 2)
        
        self.filter_entry = QLineEdit(self)
        self.grid.addWidget(self.filter_entry, 1, 3)
        self.filter_entry.textChanged.connect(self.on_filter_entry_textChanged)
        self.filter_text = ""
        
        self.filter_cb = QComboBox(self)
        self.grid.addWidget(self.filter_cb, 1, 4)
        self.filter_cb.currentIndexChanged.connect(self.on_filter_cb_IndexChanged)
        
        self.filter_btn = QPushButton("Filter!", self)
        self.grid.addWidget(self.filter_btn, 1, 5)
        self.filter_btn.clicked.connect(self.on_filter_btn_clicked)
        
        self.unfilter_btn = QPushButton("Remove Filter", self)
        self.grid.addWidget(self.unfilter_btn, 1, 6)
        self.unfilter_btn.clicked.connect(self.on_actionAll_triggered)
        
        self.log.debug("\t=> Done!")
    
    def update_filterbox(self):
        """fills the filter-combobox with the header values 
        after the model has been created and set
        """
        column_num = self.model.columnCount()
        if self.header_dic:
            columns = [self.header_dic[i] for i in self.header_dic]
        else:
            columns = [self.proxy.headerData(i, Qt.Horizontal) for i in range(column_num)]
        self.filter_cb.addItems(columns)

    def create_filter_model(self):
        """creates the filter-proxy-model on top of self.model
        """
        self.log.debug("Creating filter model...")
        self.proxy = QSortFilterProxyModel(self)
        if self.add_color_proxy:
            (allele_status_column, lab_status_column) = self.add_color_proxy
            self.log.debug("adding color filter to columns {} and {}".format(allele_status_column, lab_status_column))
            self.color_proxy = ColorProxyModel(self, allele_status_column, lab_status_column)
            self.color_proxy.setSourceModel(self.model)
            self.proxy.setSourceModel(self.color_proxy)
        else:
            self.proxy.setSourceModel(self.model)
        self.table.setSortingEnabled(True)
        self.table.setModel(self.proxy)
        
    def on_filter_cb_IndexChanged(self, index):
        """restricts RegEx filter to selected column
        """
        self.log.debug("Combobox: colum {} selected".format(index))
        self.proxy.setFilterKeyColumn(index)
    
    def on_filter_entry_textChanged(self, text):
        """stores content of filter_entry as self.text 
        """
        self.log.debug("filter text: '{}'".format(text))
        self.filter_text = text
    
    def on_filter_btn_clicked(self):
        """activates RegEx filter to current content of filter_entry and filter_cb
        """
        column = self.filter_cb.currentIndex()
        self.log.debug("Filtering column {} for '{}'".format(column, self.filter_text))
        self.proxy.setFilterKeyColumn(column)
        search = QRegExp(self.filter_text, Qt.CaseInsensitive, QRegExp.RegExp)
        self.proxy.setFilterRegExp(search)
    
    def on_header_sectionClicked(self, logicalIndex):
        """opens a dialog to choose between all unique values for this column,
        or revert to 'All'
        """
        self.log.debug("Header clicked: column {}".format(logicalIndex))
        self.logicalIndex = logicalIndex
        menuValues = QMenu(self)
        self.signalMapper = QSignalMapper(self)  
  
        self.filter_cb.setCurrentIndex(self.logicalIndex)
        self.filter_cb.blockSignals(True)
        self.proxy.setFilterKeyColumn(self.logicalIndex)
        
        valuesUnique = [str(self.model.index(row, self.logicalIndex).data())
                        for row in range(self.model.rowCount())
                        ]
        
        actionAll = QAction("All", self)
        actionAll.triggered.connect(self.on_actionAll_triggered)
        menuValues.addAction(actionAll)
        menuValues.addSeparator()
        
        for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):              
            action = QAction(actionName, self)
            self.signalMapper.setMapping(action, actionNumber)  
            action.triggered.connect(self.signalMapper.map)  
            menuValues.addAction(action)
  
        self.signalMapper.mapped.connect(self.on_signalMapper_mapped)  
  
        headerPos = self.table.mapToGlobal(self.header.pos())        
        posY = headerPos.y() + self.header.height()
        posX = headerPos.x() + self.header.sectionViewportPosition(self.logicalIndex)
  
        menuValues.exec_(QPoint(posX, posY))
      
    def on_actionAll_triggered(self):
        """reverts table to unfiltered state
        """
        self.log.debug("Unfiltering...")
        filterString = QRegExp("", Qt.CaseInsensitive, QRegExp.RegExp)
        self.proxy.setFilterRegExp(filterString)
        self.filter_entry.setText("")
  
    def on_signalMapper_mapped(self, i):
        """filters current column to mapping text
        """
        text = self.signalMapper.mapping(i).text()
        self.log.debug("Filtering column {} to '{}'".format(self.logicalIndex, text))
        filterString = QRegExp(text, Qt.CaseSensitive, QRegExp.FixedString)
        self.proxy.setFilterRegExp(filterString)