class NameCommentCell(CellItem): def __init__(self, controller, parent=None, state=None): CellItem.__init__(self, controller, parent, state) self.le = QLineEdit(self.state) self.le.returnPressed.connect(self.on_return_pressed) self.le.editingFinished.connect(self.on_return_pressed) self.widgets.append(self.le) self.set_layout() self.setMaximumWidth(130) def reloadstate(self): text = str(self.le.text()) if not text == self.state: self.cellChanged.emit(self) def on_return_pressed(self): self.cellChanged.emit(self) def value(self): return self.le.text() def setValue(self, val): self.le.setText(val) self.state = val def mouseDoubleClickEvent(self, e): CellItem.mouseDoubleClick(self, e) if e.button() == Qt.LeftButton: self.le.setFocus() e.accept()
class FloatElement(MeasElement): """Base for elements that are floating point numbers.""" def createWidget(self, parent, client): if self.value is None: self.value = 10.0 self._widget = QLineEdit(parent) self._widget.setValidator(DoubleValidator(parent)) self._widget.setText('%g' % self.value) self._widget.textChanged.connect(self._updateValue) return self._widget def _updateValue(self, text): self.value = float(text.replace(',', '.')) self.changed.emit(self.value)
class TimeEditWidget(QWidget): units = ('s', 'm', 'h', 'd') returnPressed = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent) self.setLayout(QHBoxLayout()) self.layout().setContentsMargins(0.1, 0.1, 0.1, 0.1) self.layout().setSpacing(1) self.val = QLineEdit() self.val.setValidator(QDoubleValidator(0, 1000000, 2)) self.layout().addWidget(self.val) self.unit = QComboBox() self.unit.insertItems(0, self.units) self.layout().addWidget(self.unit) self.setValue(1) self.val.returnPressed.connect(self.on_returnPressed) self.val.editingFinished.connect(self.on_returnPressed) self.unit.currentIndexChanged.connect(self.recalcValue) def value(self): val = float(self.val.text()) current_unit_index = self.unit.currentIndex() if current_unit_index == 1: # minutes val *= 60. elif current_unit_index == 2: # hours val *= 3600. elif current_unit_index == 3: # days val *= 86400. return int(val) def setValue(self, val): fmt = '%%.%df' % self.val.validator().decimals() self.val.setText(fmt % float(val)) self.unit.setCurrentIndex(0) self.currentUnit = 0 def recalcValue(self, idx): # adjust widget value to unit unit_index_current = self.currentUnit unit_index_next = idx if unit_index_next > unit_index_current: start = unit_index_current end = unit_index_next elif unit_index_next < unit_index_current: start = unit_index_next end = unit_index_current val = float(self.val.text()) factor = 1. for i in range(start, end): if self.units[i + 1] == 'd': factor *= 24. else: factor *= 60. if unit_index_next - unit_index_current > 0: factor = 1. / factor next_value = val * factor self.val.setText('%s' % next_value) self.currentUnit = idx def on_returnPressed(self): self.returnPressed.emit()
class BaseDev(QWidget): base_address = 0 has_target = False has_status = False offset = 1 def __init__(self, model, name, index, addr, has_status=False, target=None, value_offset=1): QWidget.__init__(self) self.index = index self.name = name self.model = model self.offset = value_offset self.has_status = has_status self.has_target = target is not None self.base_address = addr self._namelabel = QLabel(name) self._namelabel.setMinimumWidth(120) self._namelabel.setMaximumWidth(120) # self._groupbox = QGroupBox(name) self._groupbox = QFrame() # self._groupbox.setFlat(False) # self._groupbox.setCheckable(False) self._hlayout = QHBoxLayout() self._hlayout.addWidget(self._namelabel) self._hlayout.addWidget(self._groupbox) self._hlayout.setSpacing(0) # inside of the groupbox there is a vbox with 1 or 2 hboxes self._inner_vbox = QVBoxLayout() self._groupbox.setLayout(self._inner_vbox) # upper inner hbox self._inner_hbox1 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox1) # fill upper hbox self.valueWidget = QLineEdit('0b123456789abcdef0') self.valueWidget.setMaximumWidth(120) self._inner_hbox1.addWidget(self.valueWidget) if self.has_target: self.targetWidget = QLineEdit() self.targetWidget.setPlaceholderText(target) self.targetWidget.setMaximumWidth(120) self.targetWidget.returnPressed.connect(lambda *a: model.targeter( index, (self.targetWidget.text(), self.targetWidget.setText(''))[0])) self._inner_hbox1.addWidget(self.targetWidget) self.goButton = QPushButton('Go') self.goButton.clicked.connect(lambda *a: model.targeter( index, (self.targetWidget.text(), self.targetWidget.setText(''))[0])) self._inner_hbox1.addWidget(self.goButton) self.stopButton = QPushButton('Stop') self.stopButton.clicked.connect(lambda *a: model.stopper(index)) self._inner_hbox1.addWidget(self.stopButton) # now (conditionally) the second hbox if has_status: self._inner_hbox2 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox2) self.statvalueWidget = QLineEdit('statval') self.statvalueWidget.setMaximumWidth(120) self._inner_hbox2.addWidget(self.statvalueWidget) self.statusWidget = QLineEdit('Statusstring if available') self.statusWidget.setMaximumWidth(10000) self._inner_hbox2.addWidget(self.statusWidget) self.resetButton = QPushButton('Reset') self.resetButton.clicked.connect(lambda *a: model.resetter(index)) self._inner_hbox1.addWidget(self.resetButton) # self._inner_hbox2.addStretch(0.1) # allow space for resizing self._inner_hbox1.addStretch(1) self._inner_vbox.setSpacing(0) self._inner_vbox.setContentsMargins(0, 0, 0, 0) self._hlayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self._hlayout) self.show()
class EntryWidget(base_class, ui_class): def __init__(self, client, watcher, entry, shortKey, showTimeStamp, showTTL, parent=None): base_class.__init__(self, parent) self.setupUi(self) self.updateTimer = QTimer(self) self.updateTimer.setSingleShot(True) self.watcher = watcher self.client = client self.entry = entry self.widgetValue = None self.setupEvents() self.setupWidgetUi(shortKey, showTimeStamp, showTTL) def setupEvents(self): """Sets up all events.""" self.buttonSet.clicked.connect(self.setKey) self.buttonDel.clicked.connect(self.delKey) self.buttonWatch.clicked.connect(self.watchKey) self.client.signals.keyUpdated.connect(self.keyUpdated) self.updateTimer.timeout.connect(self.updateTimerEvent) def setupWidgetUi(self, shortKey, showTimeStamp, showTTL): """ Sets up and generate a UI according to the data type of the value and whether or not time to live or time stamp should be shown. """ entry = self.entry fm = self.labelTime.fontMetrics() margins = self.labelTime.getContentsMargins() self.labelTime.setMinimumWidth( fm.width(entry.convertTime(1.0)) + margins[0] + margins[2] + self.labelTime.sizeHint().width()) if self.watcher is None: # widget is already in watcher self.buttonWatch.hide() if shortKey: self.labelKey.setText(entry.key.rpartition('/')[2]) self.labelKey.setToolTip(entry.key) else: self.labelKey.setText(entry.key) if entry.value in ('True', 'False'): self.widgetValue = ReadOnlyCheckBox() self.layoutWidget.insertWidget(4, self.widgetValue) self.layoutWidget.insertSpacerItem( 5, QSpacerItem(56, 20, QSizePolicy.Expanding)) else: self.widgetValue = QLineEdit() self.layoutWidget.insertWidget(4, self.widgetValue) self.widgetValue.setReadOnly(True) self.widgetValue.setToolTip(entry.key) if not showTTL: self.labelTTL.hide() if not showTimeStamp: self.labelTime.hide() self.updateValues() def updateValues(self): entry = self.entry if entry.expired: setBackgroundColor(self, expiredColor) elif entry.ttl: setBackgroundColor(self, ttlColor) if isinstance(self.widgetValue, ReadOnlyCheckBox): self.widgetValue.setChecked(entry.value == 'True') else: self.widgetValue.setText(entry.value) self.labelTTL.setText(str(entry.ttl or '')) self.labelTime.setText(entry.convertTime()) if entry.ttl: # automatically refresh the value if the entry has a ttl (we don't # get timestamp updates from the server unless the value changes) time_to_update = max((entry.time + entry.ttl) - time.time(), 0) self.updateTimer.start(time_to_update * 1000) def setKey(self): """Sets the key locally and on the server.""" dlg = EntryEditDialog(self) dlg.fillEntry(self.entry) dlg.valueTime.setText('') # we want current timestamp by default dlg.valueKey.setReadOnly(True) if dlg.exec_() != QDialog.Accepted: return entry = dlg.getEntry() self.client.put(entry.key, entry) def delKey(self): if QMessageBox.question(self, 'Delete', 'Really delete?', QMessageBox.Yes | QMessageBox.No) == QMessageBox.No: return self.client.delete(self.entry.key) def watchKey(self): """Adds our key to the watcher window.""" if not self.watcher: return widget = EntryWidget(self.client, None, self.entry, False, True, True, self.watcher) self.watcher.addWidgetKey(widget) self.watcher.show() def keyUpdated(self, key, entry): if key != self.entry.key: return self.entry = entry self.updateValues() def updateTimerEvent(self): self.client.update(self.entry.key)
def _setShadow(self): self._shadowed = True QLineEdit.setText(self, self.shadowText) setForegroundColor(self, self._shadowcolor)
def setText(self, text): self._shadowed = False QLineEdit.setText(self, text) setForegroundColor(self, self._textcolor)
class BaseDev(QWidget): has_target = False has_status = False def __init__(self, model, name, addr): super(BaseDev, self).__init__() self.name = name self.model = model self.addr = addr self._namelabel = QLabel(name) self._namelabel.setMinimumWidth(120) self._namelabel.setMaximumWidth(120) # self._groupbox = QGroupBox(name) self._groupbox = QFrame() # self._groupbox.setFlat(False) # self._groupbox.setCheckable(False) self._hlayout = QHBoxLayout() self._hlayout.addWidget(self._namelabel) self._hlayout.addWidget(self._groupbox) self._hlayout.setSpacing(0) # inside of the groupbox there is a vbox with 1 or 2 hboxes self._inner_vbox = QVBoxLayout() self._groupbox.setLayout(self._inner_vbox) # upper inner hbox self._inner_hbox1 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox1) # fill upper hbox self.valueWidget = QLineEdit('0b123456789abcdef0') self.valueWidget.setMaximumWidth(120) self._inner_hbox1.addWidget(self.valueWidget) if self.has_target: self.targetWidget = QLineEdit() self.targetWidget.setPlaceholderText('') self.targetWidget.setMaximumWidth(120) self.targetWidget.returnPressed.connect(self._go_clicked) self._inner_hbox1.addWidget(self.targetWidget) self.goButton = QPushButton('Go') self.goButton.clicked.connect(self._go_clicked) self._inner_hbox1.addWidget(self.goButton) self.stopButton = QPushButton('Stop') self.stopButton.clicked.connect(self._stop_clicked) self._inner_hbox1.addWidget(self.stopButton) # now (conditionally) the second hbox if self.has_status: self._inner_hbox2 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox2) self.statvalueWidget = QLineEdit('statval') self.statvalueWidget.setMaximumWidth(120) self._inner_hbox2.addWidget(self.statvalueWidget) self.statusWidget = QLineEdit('Statusstring if available') self.statusWidget.setMaximumWidth(10000) self._inner_hbox2.addWidget(self.statusWidget) self.resetButton = QPushButton('Reset') self.resetButton.clicked.connect(self._reset_clicked) self._inner_hbox1.addWidget(self.resetButton) # self._inner_hbox2.addStretch(0.1) # allow space for resizing self._inner_hbox1.addStretch(1) self._inner_vbox.setSpacing(0) self._inner_vbox.setContentsMargins(0, 0, 0, 0) self._hlayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self._hlayout) self.show() def _go_clicked(self): self.model.targeter(self.index, self.targetWidget.text()) self.targetWidget.setText('') def _stop_clicked(self): self.model.stopper(self.index) def _reset_clicked(self): self.resetter(self.index) def _update(self): pass def _str2bin(self, value): return int(value) def _bin2str(self, value): return str(value) def _status(self, value): return "no status decoder implemented"